1
0
mirror of https://github.com/falk-werner/webfused synced 2024-10-27 20:44:08 +00:00

Compare commits

..

128 Commits

Author SHA1 Message Date
Falk Werner
e1ab67f6b4 add end-of-life notification 2023-02-11 09:57:20 +01:00
Falk Werner
f37a9342ec
Merge pull request #13 from falk-werner/increase_version
set version to 0.8.0
2020-11-14 12:31:34 +01:00
Falk Werner
03332d2f46 set version to 0.7.0 2020-11-14 12:18:04 +01:00
Falk Werner
e8f36edfce added changelog 2020-11-14 12:17:36 +01:00
Falk Werner
da174ebf22
Merge pull request #12 from falk-werner/reduce_dependency_versions
- make userdb optional
- allow to specify mount options
- fix invalid memory access of syslog logger
2020-11-14 11:43:07 +01:00
Falk Werner
e42639fc2a use webfuse 0.7.0 (allows to specify mount options) 2020-11-14 10:11:30 +01:00
Falk Werner
fa46f9fd6e fix: copy items when init from another list 2020-11-13 21:49:28 +01:00
Falk Werner
d8879cf1d9 allow to specify mount options 2020-11-13 19:29:03 +01:00
Falk Werner
3c14ba1cae fix: ensure that syslog ident is valid while logger is active 2020-11-12 11:47:09 +01:00
Falk Werner
ce2f70f230 fix: fixed version of libconfig 2020-11-11 22:24:03 +01:00
Falk Werner
dfd2cd4bc0 make userdb optional 2020-11-11 21:56:11 +01:00
Falk Werner
3c0fce8eee
Merge pull request #11 from falk-werner/update_deps
Update depencies
2020-10-18 11:17:21 +02:00
Falk Werner
8ad59f6bfa quirk: increaded timeout multiplier for tests (fix test of daemon.run) 2020-10-17 23:35:16 +02:00
Falk Werner
ea323634b1 fix: fixed typo 2020-10-17 23:02:29 +02:00
Falk Werner
977f823a61 remanded package names to match pkg-config names 2020-10-17 22:58:53 +02:00
Falk Werner
c71d04dcbe updated libwebsockets to 4.1.3; updated webfuse to 0.5.1 2020-10-17 22:56:51 +02:00
Falk Werner
ea40e93f5b fix: use sudo when installing dependencies 2020-10-17 21:40:21 +02:00
Falk Werner
de791d2788 use install_deps script from github 2020-10-14 22:43:09 +02:00
Falk Werner
0126bb53cb downgrade libwebsockets to 4.0.13 (incompatible with webfuse 0.5.0) 2020-10-14 22:28:18 +02:00
Falk Werner
c972c17bd2 updated libfuse to 3.10.0, libwebsockets to 4.1.3, libjansson to 2.13.1 2020-10-14 22:14:27 +02:00
Falk Werner
3aaf2a6792 fix gtest md5 2020-10-14 22:00:30 +02:00
Falk Werner
69655c5784 use meson compile and meson install 2020-10-14 21:49:21 +02:00
Falk Werner
4e168aa324 fix gtest version 2020-10-14 21:48:57 +02:00
Falk Werner
9487b3c2d4 removed subprojects 2020-10-14 21:25:22 +02:00
Falk Werner
1b172b5259 remove debug output 2020-10-14 21:09:19 +02:00
Falk Werner
2b4d2b31b9 fix: set LD_LIBRARY_PATH 2020-10-14 21:02:37 +02:00
Falk Werner
ef72d00d10 fix: set LD_LIBRARY_PATH 2020-10-14 20:50:36 +02:00
Falk Werner
9d4ddf271c fix: set LD_LIBRARY_PATH 2020-10-14 20:41:43 +02:00
Falk Werner
bbe3b7b669 fix: set LD_LIBRARY_PATH 2020-10-14 20:20:13 +02:00
Falk Werner
6e62076d55 updated libwebsockets to 4.0.13 2020-10-14 20:10:25 +02:00
Falk Werner
b95f537a79 print error logs on failure 2020-10-14 20:07:01 +02:00
Falk Werner
e1705d50cf install with sudo 2020-10-14 19:48:53 +02:00
Falk Werner
1d7f0c79ee fix: fixed script name 2020-10-14 19:32:02 +02:00
Falk Werner
44f809d7bd install dependencies directly instead of using subprojects 2020-10-14 19:10:31 +02:00
Falk Werner
7d5e4be311
Merge pull request #10 from falk-werner/remove_fixed_meson_version
Remove fixed meson version
2020-10-14 17:37:01 +02:00
Falk Werner
1660f74f7a chore: removed fixed meson version 2020-10-14 17:20:56 +02:00
Falk Werner
b212ecc7a6 set version to 0.6.0 2020-07-19 12:58:26 +02:00
Falk Werner
3cbf1aa1a3
Merge pull request #9 from falk-werner/update_webfuse_0.5.0
updated webfuse to 0.5.0
2020-07-19 12:53:49 +02:00
Falk Werner
449e584b30 workaround: use meson 0.54.3 to avoid build error when coverage is enabled (error in meson 0.55.0) 2020-07-19 12:35:15 +02:00
Falk Werner
5a0927c55c updated webfuse to 0.5.0 2020-07-19 12:17:23 +02:00
Falk Werner
55707126ca fix: removed dependency to gtest when building without tests 2020-07-05 12:30:26 +02:00
Falk Werner
91f72d9951 increased version to 0.5.0 2020-07-05 11:32:14 +02:00
Falk Werner
fd0b71c394
Merge pull request #8 from falk-werner/update_webfuse_to_v0.4
Update webfuse to v0.4,0
2020-07-05 11:27:39 +02:00
Falk Werner
3dbf7c4561 updated webfuse to 0.4.0 2020-07-05 11:19:00 +02:00
Falk Werner
6ac93184df changed required version of libwebsockets to 4.0.0 2020-07-05 11:10:39 +02:00
Falk Werner
c17a5749b1 updated libfuse to 3.9.1 2020-06-06 20:46:08 +02:00
Falk Werner
4fba466165 increased version to 0.4.0 2020-06-06 13:06:31 +02:00
Falk Werner
566bf39bba
Merge pull request #7 from falk-werner/meson_build
Switched build system to meson
2020-06-06 13:01:59 +02:00
Falk Werner
d03d8e9412 removed cmake build 2020-06-06 12:50:21 +02:00
Falk Werner
45ac961f57 switched build instructions to meson 2020-06-06 12:50:02 +02:00
Falk Werner
0328572c54 fixed typo 2020-06-06 12:38:29 +02:00
Falk Werner
2b77e415ce applied build matrix to meson 2020-06-06 12:30:37 +02:00
Falk Werner
4da0c4b672 enable tes execution 2020-06-06 11:39:51 +02:00
Falk Werner
b61a281949 fix: fixed meson build 2020-06-05 23:38:28 +02:00
Falk Werner
57212f1b96 fix: gmock_main dependency 2020-06-05 16:22:03 +02:00
Falk Werner
8d43061014 updated to webfuse v0.3.0 2020-06-05 16:14:18 +02:00
Falk Werner
c3ec82535d exclude build of webfuse provider and webfuse tests 2020-05-25 20:07:26 +02:00
Falk Werner
343bf6da09 removed local .deps directory 2020-05-25 20:06:25 +02:00
Falk Werner
de8411c153 switched to meson build 2020-05-25 20:05:43 +02:00
Falk Werner
6a118f3e8a skip installation of subproject 2020-05-24 22:02:29 +02:00
Falk Werner
8b11eb0ea7 switched to branch meson_build 2020-05-24 22:01:56 +02:00
Falk Werner
421c76b2e7 added basic meson.build file 2020-05-24 21:10:49 +02:00
Falk Werner
9bbe578857 fix: API of webfuse_adapter was changed in version 0.3.0 2020-05-24 21:09:41 +02:00
Falk Werner
2643b36ed8 fixed default config file path 2020-03-20 18:01:36 +01:00
Falk Werner
0353131770 increased version 2020-03-20 16:59:07 +01:00
Falk Werner
bc99cbfaab
Merge pull request #6 from falk-werner/update_libfuse
updated libfuse to 3.9.1
2020-03-20 16:56:15 +01:00
Falk Werner
f6583baf5f updated libfuse to 3.9.1 2020-03-20 16:45:52 +01:00
Falk Werner
cba0c5923c updated libfuse to 3.9.1 2020-03-20 16:40:09 +01:00
Falk Werner
dd9e9449d2 updated ignored files and directories 2020-03-20 16:38:55 +01:00
Falk Werner
944bd9913b updated version to 0.2.0 2020-03-20 16:37:34 +01:00
Falk Werner
563cbf5296
Merge pull request #5 from falk-werner/test_and_docu
refactored unit tests
2020-03-20 16:35:58 +01:00
Falk Werner
6492b0fd51 split docu 2020-03-20 16:27:48 +01:00
Falk Werner
390acffe7b split factory tests 2020-03-20 15:10:58 +01:00
Falk Werner
bd4323e53b use wrap utility 2020-03-20 14:51:57 +01:00
Falk Werner
ea56c6e86c use wrap utility 2020-03-20 14:26:41 +01:00
Falk Werner
90fc495d95 use wrap utility 2020-03-20 14:16:32 +01:00
Falk Werner
d7fd1fdf83 use wrap utility 2020-03-20 14:02:38 +01:00
Falk Werner
933789b045 refactored tests 2020-03-20 13:48:58 +01:00
Falk Werner
364d19bdea added tests for userdb 2020-03-20 13:25:58 +01:00
Falk Werner
35122136fd added daemon test 2020-03-20 11:32:45 +01:00
Falk Werner
1223363c6c set codecov badge to master 2020-03-20 10:28:36 +01:00
Falk Werner
ba270f1d0d increased test coverage 2020-03-20 10:26:41 +01:00
Falk Werner
7553846629 fixed memory leak in test 2020-03-20 09:52:56 +01:00
Falk Werner
5145129c18 fix: let valgrind fail on memcheck error 2020-03-20 09:48:59 +01:00
Falk Werner
e5aef52fdf
Merge pull request #4 from falk-werner/pam
feature: add PAM authenticator
2020-03-19 22:02:39 +01:00
Falk Werner
ca348795f3 added pam authenticator 2020-03-19 21:53:49 +01:00
Falk Werner
b53e002de0 added dependency to linux-pam 2020-03-19 18:33:16 +01:00
Falk Werner
35e63bb182
Merge pull request #3 from falk-werner/refactor_config_builder
refacator: merged wfd_config_builder into wfd_config
2020-03-19 17:34:16 +01:00
Falk Werner
ecf967ab85 refacator: merged wfd_config_builder into wfd_config 2020-03-19 17:25:26 +01:00
Falk Werner
38f5c60e7b
Merge pull request #2 from falk-werner/change_user
switch user and group when started as root
2020-03-19 12:50:20 +01:00
Falk Werner
dcc067f258 switch user and group when started as root 2020-03-19 12:42:47 +01:00
Falk Werner
d252fd7411
Merge pull request #1 from falk-werner/config_file
feature: provide settings in a config file
2020-03-18 19:41:50 +01:00
Falk Werner
46ba61e97d allow specification of multiple authenticators 2020-03-18 19:14:02 +01:00
Falk Werner
b37e95f724 added config file documentation 2020-03-18 18:49:52 +01:00
Falk Werner
1cd1b1ddff added basic tests for daemon 2020-03-18 18:00:53 +01:00
Falk Werner
adbfd45951 read log config from config file 2020-03-18 17:33:31 +01:00
Falk Werner
1625869696 refactor: generalize auth_settings 2020-03-18 10:17:17 +01:00
Falk Werner
609fbee24f added syslog logger 2020-03-18 09:38:25 +01:00
Falk Werner
5a58025e4a switches daemon to config file 2020-03-17 22:53:38 +01:00
Falk Werner
b62e9fc67b parse filesystem info 2020-03-17 21:51:04 +01:00
Falk Werner
16c5db6b2c ignore tests 2020-03-17 16:59:54 +01:00
Falk Werner
7e7cbd5d42 add authenticator to server config 2020-03-17 16:49:17 +01:00
Falk Werner
d90afed1b2 fixed include 2020-03-17 14:47:22 +01:00
Falk Werner
b5cd41d0fa added test for default log 2020-03-17 13:30:13 +01:00
Falk Werner
5e90853ecf added implementation of file_authenticator 2020-03-17 13:17:33 +01:00
Falk Werner
5dadb6240d report branch coverage 2020-03-17 13:08:42 +01:00
Falk Werner
0a19daa0ff fix: include uncovered files in coverage report 2020-03-17 10:18:25 +01:00
Falk Werner
2e81b8c23d parse authentication settings 2020-03-16 21:50:31 +01:00
Falk Werner
fab2545df1 fix: fixed LD_LIBRARY_PATH 2020-03-15 22:57:36 +01:00
Falk Werner
c10771b28a debug: locate libfuse3.so.3 2020-03-15 22:51:54 +01:00
Falk Werner
4ae6665f66 fix: set proper LD_LIBRARY_PATH to find libfuse3.so 2020-03-15 22:45:57 +01:00
Falk Werner
aaf8bcb688 refactor: use builder to create config 2020-03-15 22:35:57 +01:00
Falk Werner
f3743a6e01 renamed test 2020-03-15 21:50:11 +01:00
Falk Werner
892dd6d177 use builder to load config 2020-03-15 21:48:45 +01:00
Falk Werner
79fa1f6cbf added authentication settings (stub) 2020-03-10 21:56:15 +01:00
Falk Werner
389c27c7eb read server config 2020-03-09 23:59:36 +01:00
Falk Werner
d8670b742c log syntax errors 2020-03-09 23:25:47 +01:00
Falk Werner
7e70d396f1 ignore tests for coverage 2020-03-08 20:48:34 +01:00
Falk Werner
ad01f90bea log config errors 2020-03-08 20:29:08 +01:00
Falk Werner
03dc713649 added logging support 2020-03-08 19:45:49 +01:00
Falk Werner
b5943bd7b6 added skeleton of config 2020-03-08 16:14:55 +01:00
Falk Werner
d304c843bc separated main 2020-03-08 11:44:17 +01:00
Falk Werner
d8e1fcd426 ignore .vscode 2020-03-08 11:36:33 +01:00
Falk Werner
7169cf9b5c added valgrind 2020-03-02 22:44:22 +01:00
Falk Werner
4838740378 fix: added gtest 2020-03-02 22:37:20 +01:00
Falk Werner
1c783e84eb added code coverage 2020-03-02 22:31:11 +01:00
Falk Werner
141c857d4e added basic unit test 2020-03-02 22:18:25 +01:00
Falk Werner
207f18f4fd added dependency to libconfig 2020-03-02 21:55:39 +01:00
92 changed files with 6467 additions and 453 deletions

4
.gitignore vendored
View File

@ -1,2 +1,4 @@
/build/
/.deps/
/.vscode/
/subprojects/*
!/subprojects/*.wrap

View File

@ -16,7 +16,6 @@ addons:
- ca-certificates
- openssl
- libssl-dev
- uuid-dev
- udev
- gettext
- python3
@ -24,62 +23,30 @@ addons:
- python3-setuptools
- python3-wheel
- ninja-build
- libconfig-dev
- libpam0g-dev
- valgrind
env:
matrix:
- BUILD_TYPE=debug COVERAGE=true CHECK_OPTS=
- BUILD_TYPE=debug COVERAGE=false CHECK_OPTS=--wrap='valgrind --error-exitcode=42'
- BUILD_TYPE=release COVERAGE=false CHECK_OPTS=
- BUILD_TYPE=minsize COVERAGE=false CHECK_OPTS=
before_install:
- mkdir .deps
- cd .deps
# libfuse
- export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib:/usr/local/lib/x86_64-linux-gnu
- sudo pip3 install --system meson
- wget https://github.com/libfuse/libfuse/archive/fuse-3.9.0.tar.gz -O fuse.tar.gz
- tar -xf fuse.tar.gz
- cd libfuse-fuse-3.9.0
- mkdir .build
- cd .build
- meson ..
- ninja
- sudo ninja install
- cd ..
- cd ..
# libwebsockets
- wget https://github.com/warmcat/libwebsockets/archive/v3.2.0.tar.gz -O libwebsockets.tar.gz
- tar -xf libwebsockets.tar.gz
- cd libwebsockets-3.2.0
- mkdir .build
- cd .build
- cmake ..
- make
- sudo make install
- cd ..
- cd ..
# jansson
- wget https://github.com/akheron/jansson/archive/v2.12.tar.gz -O jansson.tar.gz
- tar -xf jansson.tar.gz
- cd jansson-2.12
- mkdir .build
- cd .build
- cmake ..
- make
- sudo make install
- cd ..
- cd ..
# libwebfuse
- wget https://github.com/falk-werner/webfuse/archive/v0.2.0.tar.gz -O webfuse.tar.gz
- tar -xf webfuse.tar.gz
- cd webfuse-0.2.0
- mkdir .build
- cd .build
- cmake -DWITHOUT_TESTS=ON ..
- make
- sudo make install
- cd ..
- cd ..
- cd ..
- bash <(curl -s https://raw.githubusercontent.com/falk-werner/install_deps/main/install_deps.sh) -s
before_script:
- mkdir build
- meson -Dbuildtype=$BUILD_TYPE -Db_coverage=$COVERAGE build
- cd build
- cmake ..
- ninja
script:
make
- meson test --print-errorlogs -t 10 $CHECK_OPTS
after_success:
- bash <(curl -s https://codecov.io/bash)

View File

@ -1,77 +0,0 @@
cmake_minimum_required (VERSION 3.10)
project(webfused VERSION 0.1.0 DESCRIPTION "Webfuse daemon")
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
find_package(PkgConfig REQUIRED)
pkg_check_modules(FUSE3 REQUIRED fuse3)
pkg_check_modules(LWS REQUIRED libwebsockets)
pkg_check_modules(JANSSON REQUIRED jansson)
pkg_check_modules(UUID REQUIRED uuid)
pkg_check_modules(OPENSSL REQUIRED openssl)
pkg_check_modules(WEBFUSE REQUIRED libwebfuse-adapter)
add_definitions(-D_FILE_OFFSET_BITS=64)
include_directories(
"src"
${WEBFUSE_INCLUDE_DIRS}
)
link_directories(
${WEBFUSE_LIBRARY_DIRS}
)
set(CMAKE_C_STANDARD 99)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(C_WARNINGS -Wall -Wextra)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
add_library(userdb STATIC
src/userdb/userdb.c
)
target_include_directories(userdb PUBLIC
${OPENSSL_INCLUDE_DIRS}
${JANSSON_INCLUDE_DIRS}
)
target_compile_options(userdb PUBLIC ${OPENSSL_CFLAGS_OTHER})
add_executable(webfused
src/daemon/main.c
)
target_link_libraries(webfused PUBLIC
userdb
${OPENSSL_LIBRARIES}
${WEBFUSE_LIBRARIES}
${UUID_LIBRARIES}
)
target_compile_options(webfused PUBLIC ${OPENSSL_CFLAGS_OTHER})
install(TARGETS webfused DESTINATION bin)
add_executable(webfuse-passwd
src/passwd/main.c
)
target_link_libraries(webfuse-passwd PUBLIC
userdb
${OPENSSL_LIBRARIES}
${JANSSON_LIBRARIES}
)
target_include_directories(webfuse-passwd PUBLIC
example/passwd
example/lib/userdb/include
${OPENSSL_INCLUDE_DIRS}
${JANSSON_INCLUDE_DIRS}
)
target_compile_options(webfuse-passwd PUBLIC ${OPENSSL_CFLAGS_OTHER})
install(TARGETS webfuse-passwd DESTINATION bin)

View File

@ -1,78 +1,22 @@
[![Build Status](https://travis-ci.org/falk-werner/webfused.svg?branch=master)](https://travis-ci.org/falk-werner/webfused)
[![codecov](https://codecov.io/gh/falk-werner/webfused/branch/master/graph/badge.svg)](https://codecov.io/gh/falk-werner/webfused)
# webfused
# Webfuse Daemon
Reference implementation of webfuse daemon.
Reference implementation of webfuse daemon (webfused).
## Build and run
**Note:** This repository refers to [webfuse-legacy](https://github.com/falk-werner/webfuse/tree/webfuse-legacy).
Since `webfuse-legacy` is out-dated, the repository is archived and will be removed in future.
_Please leave an issue if you are still interested in this code._
To install dependecies, see below.
## Further information
cd webfused
mkdir build
cd build
cmake ..
make
./webfused -m test --port=4711
- [Build Instructions](doc/build.md)
- [Configuration](doc/config.md)
- [Webfuse Protocol Specification](https://github.com/falk-werner/webfuse/blob/master/doc/protocol.md)
## Dependencies
## Fellow Repositories
- [webfuse](https://github.com/falk-werner/webfuse)
- [libfuse](https://github.com/libfuse/libfuse/)
- [libwebsockets](https://libwebsockets.org/)
- [jansson](https://github.com/akheron/jansson)
- [openssl](https://www.openssl.org/)
### Installing dependencies
#### libfuse
To install libfuse, meson is needed. Please refer to [meson quick guide](https://mesonbuild.com/Quick-guide.html) for setup instructions.
wget https://github.com/libfuse/libfuse/archive/fuse-3.9.0.tar.gz -O fuse.tar.gz
tar -xf fuse.tar.gz
cd libfuse-fuse-3.9.0
mkdir .build
cd .build
meson ..
ninja
sudo ninja install
#### libwebsockets
wget https://github.com/warmcat/libwebsockets/archive/v3.2.0.tar.gz -O libwebsockets.tar.gz
tar -xf libwebsockets.tar.gz
cd libwebsockets-3.2.0
mkdir .build
cd .build
cmake ..
make
sudo make install
#### jansson
wget https://github.com/akheron/jansson/archive/v2.12.tar.gz -O jansson.tar.gz
tar -xf jansson.tar.gz
cd jansson-2.12
mkdir .build
cd .build
cmake ..
make
sudo make install
#### openssl
sudo apt update
sudo install openssl libssl-dev
#### webfuse
wget https://github.com/falk-werner/webfuse/archive/v0.2.0.tar.gz -O webfuse.tar.gz
tar -xf webfuse.tar.gz
cd webfuse-0.2.0
mkdir .build
cd .build
cmake -DWITHOUT_TESTS=ON ..
make
sudo make install
- **[webfuse](https://github.com/falk-werner/webfuse)**: webfuse library
- **[webfuse-example](https://github.com/falk-werner/webfuse-example)**: example of webfuse
- **[webfuse-provider](https://github.com/falk-werner/webfuse-provider)**: reference implementation of webfuse provider

42
changelog.md Normal file
View File

@ -0,0 +1,42 @@
# webfused changelog
## 0.7.0 _(unknown)_
* __Chore:__ added changelog
## 0.6.0 _(Sat Nov 14 2020)_
* __Feature:__ allow to specify mount options via config file
* __Feature:__ make userdb optional
* __Feature:__ reduce versions of depencies to required minimum
* __Chore:__ updated dependencies (libwebsockets 4.1.3, libjansson 2.13.1, libfuse 3.10.0, webfuse 0.7.0)
* __Chore:__ remove meson subprojects (use install_deps to fetch depedencies)
* __Fix:__ ensure that syslog ident is valid while logger is active (invalid memory access)
## 0.5.0 _(Sun Jul 19 2020)_
* __Chore:__ updated depedencies (webfuse 0.5.0)
## 0.4.1 _(Sun Jul 05 2020)_
* __Fix:__ removed gtest dependency, when built without tests
## 0.4.0 _(Sun Jul 05 2020)_
* __Feature:__ allow to build without tests
* __Chore:__ updated dependencies (libwebsockets 4.0.0, webfuse 0.4.0)
## 0.3.0 _(Sat Jun 06 2020)_
* __Chore:__ switched build system to meson
## 0.2.0 _(Fri Mar 20 2020)_
* __Feature:__ enabled authentication (pam, userdb)
* __Feature:__ use config file
* __Feature:__ added syslog logger
## 0.1.0 _(Mon Mar 09 2020)_
* __Feature:__ initial version

4
codecov.yml Normal file
View File

@ -0,0 +1,4 @@
ignore:
- "test"
- "src/passwd"
- "src/webfused/main.c"

31
deps.sh Normal file
View File

@ -0,0 +1,31 @@
PACKAGES="fuse3 libwebsockets jansson gtest webfuse"
fuse3_VERSION=3.10.0
fuse3_URL=https://github.com/libfuse/libfuse/archive/fuse-${fuse3_VERSION}.tar.gz
fuse3_MD5=22aec9bc9008eea6b17e203653d1b938
fuse3_DIR=libfuse-fuse-${fuse3_VERSION}
fuse3_TYPE=meson
libwebsockets_VERSION=4.1.3
libwebsockets_URL=https://github.com/warmcat/libwebsockets/archive/v${libwebsockets_VERSION}.tar.gz
libwebsockets_MD5=413cbe790ccb089001f53b2ee167b9c2
libwebsockets_DIR=libwebsockets-${libwebsockets_VERSION}
libwebsockets_TYPE=cmake
jansson_VERSION=2.13.1
jansson_URL=https://github.com/akheron/jansson/archive/v${jansson_VERSION}.tar.gz
jansson_MD5=3d589a62053874893715453a46a32a0e
jansson_DIR=jansson-${jansson_VERSION}
jansson_TYPE=cmake
gtest_VERSION=1.10.0
gtest_URL=https://github.com/google/googletest/archive/release-${gtest_VERSION}.tar.gz
gtest_MD5=ecd1fa65e7de707cd5c00bdac56022cd
gtest_DIR=googletest-release-${gtest_VERSION}
gtest_TYPE=cmake
webfuse_VERSION=0.7.0
webfuse_URL=https://github.com/falk-werner/webfuse/archive/v${webfuse_VERSION}.tar.gz
webfuse_MD5=4f8b69196a634016da3c0e4f63e13590
webfuse_DIR=webfuse-${webfuse_VERSION}
webfuse_TYPE=meson

97
doc/build.md Normal file
View File

@ -0,0 +1,97 @@
# Build Instructions
To install dependecies, see below.
meson build
cd build
ninja
./webfused -f webfused.conf
## Dependencies
- [webfuse](https://github.com/falk-werner/webfuse)
- [libfuse](https://github.com/libfuse/libfuse/)
- [libwebsockets](https://libwebsockets.org/)
- [jansson](https://github.com/akheron/jansson)
- [openssl](https://www.openssl.org/)
- [libconfig](https://hyperrealm.github.io/libconfig/)
- [linux-pam](http://www.linux-pam.org/)
- [Google Test](https://github.com/google/googletest) *(Test only)*
It is recommended to provide all dependencies outside of the project.
To simply development, some dependencies are bundled using meson wrap files. Note that installing webfused will also install subprojects, when they are used (this is typically not what you want).
### libfuse
To install libfuse, meson is needed. Please refer to [meson quick guide](https://mesonbuild.com/Quick-guide.html) for setup instructions.
wget https://github.com/libfuse/libfuse/archive/fuse-3.9.1.tar.gz -O fuse.tar.gz
tar -xf fuse.tar.gz
cd libfuse-fuse-3.9.1
mkdir .build
cd .build
meson ..
ninja
sudo ninja install
### libwebsockets
wget https://github.com/warmcat/libwebsockets/archive/v4.0.13.tar.gz -O libwebsockets.tar.gz
tar -xf libwebsockets.tar.gz
cd libwebsockets-4.0.13
mkdir .build
cd .build
cmake ..
make
sudo make install
### jansson
wget https://github.com/akheron/jansson/archive/v2.12.tar.gz -O jansson.tar.gz
tar -xf jansson.tar.gz
cd jansson-2.12
mkdir .build
cd .build
cmake ..
make
sudo make install
### openssl
sudo apt update
sudo install openssl libssl-dev
### webfuse
wget https://github.com/falk-werner/webfuse/archive/v0.2.0.tar.gz -O webfuse.tar.gz
tar -xf webfuse.tar.gz
cd webfuse-0.2.0
mkdir .build
cd .build
cmake -DWITHOUT_TESTS=ON ..
make
sudo make install
### libconfig
sudo apt update
sudo apt install libconfig-dev
### linux-pam
sudo apt update
sudo apt install libpam0g-dev
### GoogleTest
Installation of GoogleTest is optional webfuse library, but required to compile tests.
wget -O gtest-1.10.0.tar.gz https://github.com/google/googletest/archive/release-1.10.0.tar.gz
tar -xf gtest-1.10.0.tar.gz
cd googletest-release-1.10.0
mkdir .build
cd .build
cmake ..
make
sudo make install

168
doc/config.md Normal file
View File

@ -0,0 +1,168 @@
# Configuration
A config file is used to configure webfuse daemon.
## Config file
```
version = { major = 1, minor = 1 }
server:
{
vhost_name = "localhost"
port = 8080
tls:
{
certificate = "/etc/webfused/cert.pem"
key = "/etc/webfused/key.pem"
}
document_root = "/var/www"
}
authentication:
(
{
provider = "pam"
settings:
{
service_name = "webfused"
}
}
)
filesystems:
(
{name = "test", mount_point = "/tmp/webfused", mount_options = () }
)
log:
{
provider: "syslog"
level: "warning"
settings:
{
ident = "webfused"
facility = "daemon"
log_pid = true
}
}
user:
{
name = "webfused"
group = "webfused"
}
```
## Version
The version sections specifies the schema version of the config file.
Currently, there is only one schema version defined: 1.0
## Server
| Setting | Type | Default value | Description |
| ------------- | ------ | ------------- | ------------------------ |
| vhostname | string | localhost | Name of the virtual host |
| port | int | 8080 | Port number of server |
| document_root | string | *-empty-* | Path of HTTP files |
| tls | object | *-empty-* | see below |
When *document_root* is omitted, no HTTP files are served.
### TLS
| Setting | Type | Default value | Description |
| ----------- | ------ | ------------- | ------------------------------------------- |
| certificate | string | *-empty-* | Path to servers own certificate (.pem file) |
| key | string | *-empty-* | Path to servers own private key (.pem file) |
TLS is only activated, when both, *certificate* and *key* are specified.
Otherwise, plain websockes without TLS are used.
## Authentication
| Setting | Type | Default value | Description |
| -------- | ------ | ------------- | ----------------------------------------------- |
| provider | string | *-required-* | Name of the authentication provider (see below) |
| settings | object | *-empty-* | Provider specific settings (see below)
Currently, the following providers are supported:
- *file*: file based authentication
- *pam*: authentication based on Linux PAM
## File Authenticaton Provider
Allows authentication against a file containing username and password.
| Setting | Type | Default value | Description |
| -------- | ------ | ------------- | ------------------------------- |
| file | string | *-required-* | Path to the authentication file |
## PAM Authenticaton Provider
Allows authentication using Linux PAM.
| Setting | Type | Default value | Description |
| ------------ | ------ | ------------- | ---------------------- |
| service_name | string | webfused | PAM service identifier |
## Filesystems
Contains a list of file systems that can be provided by webfuse providers.
| Setting | Type | Default value | Description |
| ----------- | ------ | ------------- | ---------------------------------- |
| name | string | *-required-* | Name of the filesystem |
| mount_point | string | *-required-* | Local path to mount the filesystem |
## Log
| Setting | Type | Default value | Description |
| ----------- | ------ | ------------- | -------------------------------------- |
| provider | string | *-required-* | Name of log provider (see below) |
| level | string | *-required-* | Log level (see below) |
| settings | object | *-empty-* | Provider specific settings (see below) |
The following log levels are supported:
- *none*: diabled logging
- *fatal*: log only fatal errors
- *error*: log all kind of errors
- *warn*: log errors and warnings
- *info*: log info messages, warnings and errors
- *debug*: log debug and info messages as well as warnings and errors
- *all*: log all kind of messages
Currently, the following providers are available:
- *stderr*: logs to console error output
- *syslog*: logs to syslog
### Stderr Logger
This logger does not provide any settings.
### Syslog Logger
| Setting | Type | Default value | Description |
| ----------- | ------ | ------------- | ------------------------------------------ |
| ident | string | webfused | Syslog ident (see syslog documentation) |
| facility | string | daemon | Syslog facility (see syslog documentation) |
| log_pid | bool | false | Add process ID to log messages |
## User
| Setting | Type | Default value | Description |
| ------- | ------ | ------------- | ------------------------------- |
| name | string | *-required-* | Name of the user to switch to. |
| group | string | *-required-* | Name of the group to switch to. |
Webfuse daemon will not run as root. If started as root, webfuse daemon tries to
switch to *user* and *group* provided in config file.
*Note*: user and group are not switched, when webfuse daemon is not started as root.

58
etc/webfused.conf Normal file
View File

@ -0,0 +1,58 @@
# Webfuse deamon configuration file
version = { major = 1, minor = 1 }
server:
{
vhost_name = "localhost"
port = 8080
# tls:
# {
# certificate = "/etc/webfused/cert.pem"
# key = "/etc/webfused/key.pem"
# }
# document_root = "/var/www"
}
authentication:
(
{
provider = "file"
settings:
{
file = "/etc/webfused/passwd"
}
}
# {
# provider = "pam"
# settings:
# {
# service_name = "webfused"
# }
# }
)
filesystems:
(
{name = "test", mount_point = "/tmp/webfused", mount_options = () }
)
log:
{
provider: "syslog"
level: "warning"
settings:
{
ident = "webfused"
facility = "daemon"
log_pid = true
}
}
#user:
#{
# name = "webfused"
# group = "webfused"
#}

170
meson.build Normal file
View File

@ -0,0 +1,170 @@
project('webfused', 'c', 'cpp', version: '0.7.0', license: 'LGPL-3.0+',
default_options: ['c_std=gnu99', 'cpp_std=gnu++14'])
without_tests = get_option('without_tests')
without_userdb = get_option('without_userdb')
c_compiler = meson.get_compiler('c')
libconfig_dep = dependency('libconfig', version: '>=1.5')
pam_dep = c_compiler.find_library('pam')
libwebsockets_dep = dependency('libwebsockets', version: '>=4.0.0')
libfuse_dep = dependency('fuse3', version: '>=3.1.0')
webfuse_adapter_dep = dependency('webfuse', version: '>=0.7.0')
inc_dir = include_directories('src')
if not without_userdb
openssl_dep = dependency('openssl', version: '>=1.1.1')
jansson_dep = dependency('jansson', version: '>=2.7')
libuserdb = static_library('userdb',
'src/userdb/userdb_openssl.c',
include_directories: inc_dir,
dependencies: [openssl_dep, jansson_dep])
libuserdb_dep = declare_dependency(
include_directories: inc_dir,
link_with: libuserdb,
dependencies: [openssl_dep, jansson_dep])
else
libuserdb = static_library('userdb',
'src/userdb/userdb_none.c',
include_directories: inc_dir)
libuserdb_dep = declare_dependency(
include_directories: inc_dir,
link_with: libuserdb)
endif
libwebfused = static_library('webfused',
'src/webfused/daemon.c',
'src/webfused/mountpoint_factory.c',
'src/webfused/change_user.c',
'src/webfused/config/config.c',
'src/webfused/config/factory.c',
'src/webfused/config/settings.c',
'src/webfused/auth/authenticator.c',
'src/webfused/auth/factory.c',
'src/webfused/auth/file_authenticator.c',
'src/webfused/auth/pam_authenticator.c',
'src/webfused/log/log.c',
'src/webfused/log/logger.c',
'src/webfused/log/manager.c',
'src/webfused/log/stderr_logger.c',
'src/webfused/log/syslog_logger.c',
'src/webfused/util/string_list.c',
include_directories: inc_dir,
dependencies: [libuserdb_dep, webfuse_adapter_dep, libconfig_dep, pam_dep],
install: false)
libwebfused_dep = declare_dependency(
include_directories: inc_dir,
link_with: libwebfused,
dependencies: [libuserdb_dep, webfuse_adapter_dep, libconfig_dep, pam_dep])
webfused = executable('webfused',
'src/webfused/main.c',
include_directories: inc_dir,
dependencies: [libwebfused_dep],
install: true)
install_data('etc/webfused.conf', install_dir: '/etc')
if not without_tests
gtest_dep = dependency('gtest', version: '>=1.10.0', fallback: ['gtest', 'gtest_dep'])
gmock_main_dep = dependency('gmock_main', version: '>=1.10.0', fallback: ['gtest', 'gmock_main_dep'])
webfused_conf = configure_file(input: 'etc/webfused.conf' , output: 'webfused.conf' , copy: true)
invalid_conf = configure_file(input: 'test/invalid.conf' , output: 'invalid.conf' , copy: true)
test_passwd_json = configure_file(input: 'test/test_passwd.json', output: 'test_passwd.json', copy: true)
alltests_sources = [
'test/mock/config_builder.cc',
'test/mock/logger.cc',
'test/mock/credentials.cc',
'test/mock/settings.cc',
'test/mock/pam.cc',
'test/mock/libconfig.cc',
'test/mock/linux.cc',
'test/mock/server.cc',
'test/config/configfile.cc',
'test/config/configfile_version.cc',
'test/config/configfile_server.cc',
'test/config/configfile_auth.cc',
'test/config/configfile_filesystem.cc',
'test/config/configfile_log.cc',
'test/config/configfile_user.cc',
'test/config/config.cc',
'test/config/settings.cc',
'test/auth/factory.cc',
'test/auth/pam_authenticator.cc',
'test/log/log.cc',
'test/log/log_manager.cc',
'test/log/stderr_logger.cc',
'test/log/syslog_logger.cc',
'test/util/string_list.cc',
'test/daemon.cc',
'test/change_user.cc',
'test/mountpoint_factory.cc'
]
if not without_userdb
alltests_sources += [
'test/auth/file_authenticator.cc',
'test/userdb.cc'
]
endif
alltests = executable('alltests',
alltests_sources,
include_directories: ['src', 'test'],
link_args: [
'-Wl,--wrap=wf_credentials_type',
'-Wl,--wrap=wf_credentials_get',
'-Wl,--wrap=wf_server_create',
'-Wl,--wrap=wfd_settings_get_string',
'-Wl,--wrap=wfd_settings_get_string_or_default',
'-Wl,--wrap=wfd_settings_get_bool',
'-Wl,--wrap=wfd_config_create',
'-Wl,--wrap=wfd_config_dispose',
'-Wl,--wrap=wfd_config_set_server_vhostname',
'-Wl,--wrap=wfd_config_set_server_port',
'-Wl,--wrap=wfd_config_set_server_key',
'-Wl,--wrap=wfd_config_set_server_cert',
'-Wl,--wrap=wfd_config_set_server_document_root',
'-Wl,--wrap=wfd_config_add_auth_provider',
'-Wl,--wrap=wfd_config_add_filesystem',
'-Wl,--wrap=wfd_config_set_logger',
'-Wl,--wrap=wfd_config_set_user',
'-Wl,--wrap=pam_start',
'-Wl,--wrap=pam_end',
'-Wl,--wrap=pam_strerror',
'-Wl,--wrap=pam_authenticate',
'-Wl,--wrap=pam_acct_mgmt',
'-Wl,--wrap=config_setting_get_elem',
'-Wl,--wrap=getuid',
'-Wl,--wrap=getgrnam',
'-Wl,--wrap=setgid',
'-Wl,--wrap=setgroups',
'-Wl,--wrap=getpwnam',
'-Wl,--wrap=setuid'
],
dependencies: [
libwebfused_dep,
gtest_dep,
gmock_main_dep])
test('alltests', alltests)
endif

2
meson_options.txt Normal file
View File

@ -0,0 +1,2 @@
option('without_tests', type: 'boolean', value: false, description: 'disable unit tests')
option('without_userdb', type: 'boolean', value: false, description: 'disable userdb')

View File

@ -1,196 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#include <stdbool.h>
#include <signal.h>
#include <unistd.h>
#include <getopt.h>
#include <webfuse_adapter.h>
#include <userdb/userdb.h>
#define SERVICE_TIMEOUT (1 * 1000)
struct args
{
struct wf_server_config * config;
char * passwd_path;
bool show_help;
};
static bool shutdown_requested = false;
static void show_help(void)
{
printf(
"webfused, Copyright (c) 2019, webfused authors <https://github.com/falk-werner/webfused>\n"
"Websocket file system daemon\n"
"\n"
"Usage: webfused [m <mount_point>] [-d <document_root] [-n <vhost_name>] [-p <port>]\n"
" [-c <server_cert_path>] [-k <server_key_path>] [-P <passwd_path>]\n"
"\n"
"Options:\n"
"\t-m, --mount_point Path of mount point (required)\n"
"\t-d, --document_root Path of www directory (default: not set, www disabled)\n"
"\t-c, --server_cert_path Path of servers own certificate (default: not set, TLS disabled)\n"
"\t-k, --server_key_path Path of servers private key (default: not set, TLS disabled)\n"
"\t-n, --vhost_name Name of virtual host (default: \"localhost\")\n"
"\t-p, --port Number of servers port (default: 8080)\n"
"\t-P, --passwd_path Path to password file (default: not set, authentication disabled)\n"
"\n");
}
static bool authenticate(struct wf_credentials * creds, void * user_data)
{
bool result = false;
struct args * args = user_data;
char const * username = wf_credentials_get(creds, "username");
char const * password = wf_credentials_get(creds, "password");
if ((NULL != username) && (NULL != password))
{
struct userdb * db = userdb_create("");
result = userdb_load(db, args->passwd_path);
if (result)
{
result = userdb_check(db, username, password);
}
userdb_dispose(db);
}
return result;
}
static int parse_arguments(int argc, char * argv[], struct args * args)
{
static struct option const options[] =
{
{"mount_point", required_argument, NULL, 'm'},
{"document_root", required_argument, NULL, 'd'},
{"server_cert_path", required_argument, NULL, 'c'},
{"server_key_path", required_argument, NULL, 'k'},
{"vhost_name", required_argument, NULL, 'n'},
{"port", required_argument, NULL, 'p'},
{"passwd_path", required_argument, NULL, 'P'},
{"help", no_argument, NULL, 'h'},
{NULL, 0, NULL, 0}
};
bool result = EXIT_SUCCESS;
bool finished = false;
bool has_mountpoint = false;
while ((!finished) && (EXIT_SUCCESS == result))
{
int option_index = 0;
int const c = getopt_long(argc, argv, "m:d:c:k:n:p:P:h", options, &option_index);
switch (c)
{
case -1:
finished = true;
break;
case 'h':
args->show_help = true;
finished = true;
break;
case 'm':
wf_server_config_set_mountpoint(args->config, optarg);
has_mountpoint = true;
break;
case 'd':
wf_server_config_set_documentroot(args->config, optarg);
break;
case 'c':
wf_server_config_set_certpath(args->config, optarg);
break;
case 'k':
wf_server_config_set_keypath(args->config, optarg);
break;
case 'n':
wf_server_config_set_vhostname(args->config, optarg);
break;
case 'p':
wf_server_config_set_port(args->config, atoi(optarg));
break;
case 'P':
free(args->passwd_path);
args->passwd_path = strdup(optarg);
wf_server_config_add_authenticator(args->config,
"username",
&authenticate,
args);
break;
default:
fprintf(stderr, "error: unknown argument\n");
result = EXIT_FAILURE;
break;
}
}
if ((EXIT_SUCCESS == result) && (!args->show_help))
{
if (!has_mountpoint)
{
fprintf(stderr, "error: missing mount point\n");
result = EXIT_FAILURE;
}
}
if (EXIT_SUCCESS != result)
{
args->show_help = true;
}
return result;
}
static void on_interrupt(int signal_id)
{
(void) signal_id;
shutdown_requested = true;
}
int main(int argc, char * argv[])
{
struct args args;
args.config = wf_server_config_create();
wf_server_config_set_vhostname(args.config, "localhost");
wf_server_config_set_port(args.config, 8080);
args.passwd_path = NULL;
args.show_help = false;
int result = parse_arguments(argc, argv, &args);
if (!args.show_help)
{
signal(SIGINT, on_interrupt);
struct wf_server * server = wf_server_create(args.config);
if (NULL != server)
{
while (!shutdown_requested)
{
wf_server_service(server, SERVICE_TIMEOUT);
}
wf_server_dispose(server);
}
else
{
fprintf(stderr, "fatal: unable start server\n");
result = EXIT_FAILURE;
}
}
else
{
show_help();
}
free(args.passwd_path);
wf_server_config_dispose(args.config);
return result;
}

View File

@ -10,7 +10,6 @@
#include <openssl/opensslv.h>
#include <openssl/engine.h>
#include <openssl/evp.h>
#include <jansson.h>
#include <userdb/userdb.h>
@ -131,7 +130,7 @@ static int parse_args(struct args * args, int argc, char * argv[])
fprintf(stderr, "error: missing command\n");
args->show_help = true;
result = EXIT_FAILURE;
}
}
}
return result;
@ -173,7 +172,7 @@ static int add_user(struct args * args)
}
struct userdb * db = userdb_create(args->pepper);
userdb_load(db, args->file);
userdb_load_file(db, args->file);
userdb_add(db, args->username, args->password);
bool result = userdb_save(db, args->file);
userdb_dispose(db);
@ -191,7 +190,7 @@ static int remove_user(struct args * args)
}
struct userdb * db = userdb_create(args->pepper);
userdb_load(db, args->file);
userdb_load_file(db, args->file);
userdb_remove(db, args->username);
bool result = userdb_save(db, args->file);
userdb_dispose(db);
@ -216,7 +215,7 @@ static int check_password(struct args * args)
}
struct userdb * db = userdb_create(args->pepper);
userdb_load(db, args->file);
userdb_load_file(db, args->file);
bool result = userdb_check(db, args->username, args->password);
userdb_dispose(db);
@ -301,4 +300,4 @@ int main(int argc, char * argv[])
args_cleanup(&args);
openssl_cleanup();
return result;
}
}

View File

@ -21,10 +21,14 @@ extern bool userdb_save(
struct userdb * db,
char const * filename);
extern bool userdb_load(
extern bool userdb_load_file(
struct userdb * db,
char const * filename);
extern bool userdb_load_string(
struct userdb * db,
char const * contents);
extern void userdb_add(
struct userdb * db,
char const * username,

74
src/userdb/userdb_none.c Normal file
View File

@ -0,0 +1,74 @@
#include "userdb.h"
#include <stddef.h>
struct userdb * userdb_create(
char const * pepper)
{
(void) pepper;
return NULL;
}
void userdb_dispose(struct userdb * db)
{
(void) db;
}
bool userdb_save(
struct userdb * db,
char const * filename)
{
(void) db;
(void) filename;
return false;
}
bool userdb_load_file(
struct userdb * db,
char const * filename)
{
(void) db;
(void) filename;
return false;
}
bool userdb_load_string(
struct userdb * db,
char const * contents)
{
(void) db;
(void) contents;
return false;
}
void userdb_add(
struct userdb * db,
char const * username,
char const * password)
{
(void) db;
(void) username;
(void) password;
}
void userdb_remove(
struct userdb * db,
char const * user)
{
(void) db;
(void) user;
}
bool userdb_check(
struct userdb * db,
char const * username,
char const * password)
{
(void) db;
(void) username;
(void) password;
return false;
}

View File

@ -77,20 +77,17 @@ static char hex_char(unsigned char value)
static char * to_hex(unsigned char const * value, size_t length)
{
char * result = malloc((2 * length) + 1);
if (NULL != result)
for (size_t i = 0, j = 0; i < length; i++, j+=2)
{
for (size_t i = 0, j = 0; i < length; i++, j+=2)
{
unsigned char high = (value[i] >> 4) & 0x0f;
unsigned char low = value[i] & 0x0f;
unsigned char high = (value[i] >> 4) & 0x0f;
unsigned char low = value[i] & 0x0f;
result[j ] = hex_char(high);
result[j + 1] = hex_char(low);
}
result[2 * length] = '\0';
result[j ] = hex_char(high);
result[j + 1] = hex_char(low);
}
result[2 * length] = '\0';
return result;
}
@ -120,21 +117,46 @@ static char * compute_hash(
}
char * result = NULL;
EVP_MD_CTX * context = EVP_MD_CTX_new();
EVP_DigestInit_ex(context, digest, NULL);
EVP_DigestUpdate(context, password, strlen(password));
EVP_DigestUpdate(context, salt, strlen(salt));
EVP_DigestUpdate(context, db->pepper, strlen(db->pepper));
unsigned int hash_size = EVP_MD_size(digest);
unsigned char * hash = malloc(hash_size);
EVP_DigestFinal_ex(context, hash, &hash_size);
EVP_MD_CTX_free(context);
if (NULL != hash)
result = to_hex(hash, hash_size);
free(hash);
return result;
}
static bool userdb_load(
struct userdb * db,
json_t * container)
{
bool result = false;
if (NULL != container)
{
EVP_MD_CTX * context = EVP_MD_CTX_new();
EVP_DigestInit_ex(context, digest, NULL);
EVP_DigestUpdate(context, password, strlen(password));
EVP_DigestUpdate(context, salt, strlen(salt));
EVP_DigestUpdate(context, db->pepper, strlen(db->pepper));
EVP_DigestFinal_ex(context, hash, &hash_size);
EVP_MD_CTX_free(context);
json_t * meta = json_object_get(container, "meta");
json_t * users = json_object_get(container, "users");
result = to_hex(hash, hash_size);
free(hash);
if ((is_compatible(meta)) && (json_is_object(users))) {
json_t * hash_algorithm = json_object_get(meta, "hash_algorithm");
free(db->hash_algorithm);
db->hash_algorithm = strdup(json_string_value(hash_algorithm));
json_decref(db->users);
json_incref(users);
db->users = users;
result = true;
}
json_decref(container);
}
return result;
@ -144,12 +166,9 @@ struct userdb * userdb_create(
char const * pepper)
{
struct userdb * db = malloc(sizeof(struct userdb));
if (NULL != db)
{
db->users = json_object();
db->pepper = strdup(pepper);
db->hash_algorithm = strdup(USERDB_HASH_ALGORITHM);
}
db->users = json_object();
db->pepper = strdup(pepper);
db->hash_algorithm = strdup(USERDB_HASH_ALGORITHM);
return db;
}
@ -184,36 +203,23 @@ bool userdb_save(
return (0 == result);
}
bool userdb_load(
bool userdb_load_file(
struct userdb * db,
char const * filename)
{
bool result = false;
json_t * container = json_load_file(filename, 0, NULL);
if (NULL != container)
{
json_t * meta = json_object_get(container, "meta");
json_t * users = json_object_get(container, "users");
if ((is_compatible(meta)) && (json_is_object(users))) {
json_t * hash_algorithm = json_object_get(meta, "hash_algorithm");
free(db->hash_algorithm);
db->hash_algorithm = strdup(json_string_value(hash_algorithm));
json_decref(db->users);
json_incref(users);
db->users = users;
result = true;
}
json_decref(container);
}
return result;
return userdb_load(db, container);
}
bool userdb_load_string(
struct userdb * db,
char const * contents)
{
json_t * container = json_loads(contents, 0, NULL);
return userdb_load(db, container);
}
void userdb_add(
struct userdb * db,
char const * username,
@ -243,7 +249,7 @@ static char const * json_object_get_string(
json_t * object,
char const * key)
{
char const * result = NULL;
char const * result = "";
json_t * string_holder = json_object_get(object, key);
if (json_is_string(string_holder))

View File

@ -0,0 +1,24 @@
#include "webfused/auth/authenticator.h"
void
wfd_authenticator_dispose(
struct wfd_authenticator authenticator)
{
authenticator.vtable->dispose(authenticator.data);
}
extern bool
wfd_authenticator_authenticate(
struct wfd_authenticator authenticator,
struct wf_credentials * credentials)
{
return authenticator.vtable->authenticate(
credentials, authenticator.data);
}
char const *
wfd_authenticator_get_type(
struct wfd_authenticator authenticator)
{
return authenticator.vtable->get_type(authenticator.data);
}

View File

@ -0,0 +1,49 @@
#ifndef WFD_AUTH_AUTHENTICATOR_H
#define WFD_AUTH_AUTHENTICATOR_H
#include "webfuse/authenticate.h"
#ifdef __cplusplus
extern "C"
{
#endif
typedef void
wfd_authenticator_dispose_fn(
void * data);
typedef char const *
wfd_authenticator_get_type_fn(
void * data);
struct wfd_authenticator_vtable
{
wfd_authenticator_dispose_fn * dispose;
wf_authenticate_fn * authenticate;
wfd_authenticator_get_type_fn * get_type;
};
struct wfd_authenticator
{
struct wfd_authenticator_vtable const * vtable;
void * data;
};
extern void
wfd_authenticator_dispose(
struct wfd_authenticator authenticator);
extern bool
wfd_authenticator_authenticate(
struct wfd_authenticator authenticator,
struct wf_credentials * credentials);
extern char const *
wfd_authenticator_get_type(
struct wfd_authenticator authenticator);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,30 @@
#include "webfused/auth/factory.h"
#include "webfused/auth/file_authenticator.h"
#include "webfused/auth/pam_authenticator.h"
#include "webfused/config/settings.h"
#include "webfused/log/log.h"
#include <string.h>
bool
wfd_authenticator_create(
char const * provider,
struct wfd_settings * settings,
struct wfd_authenticator * authenticator)
{
bool result = false;
if (0 == strcmp("file", provider))
{
result = wfd_file_authenticator_create(settings, authenticator);
}
else if (0 == strcmp("pam", provider))
{
result = wfd_pam_authenticator_create(settings, authenticator);
}
else
{
WFD_ERROR("failed to create authenticator: unknown type \"%s\"", provider);
}
return result;
}

View File

@ -0,0 +1,26 @@
#ifndef WFD_AUTHENTICATION_FACTORY_H
#define WFD_AUTHENTICATION_FACTORY_H
#ifndef __cplusplus
#include <stdbool.h>
#endif
#ifdef __cplusplus
extern "C"
{
#endif
struct wfd_authenticator;
struct wfd_settings;
extern bool
wfd_authenticator_create(
char const * provider,
struct wfd_settings * settings,
struct wfd_authenticator * authenticator);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,91 @@
#include "webfused/auth/file_authenticator.h"
#include "webfused/auth/authenticator.h"
#include "webfused/config/settings.h"
#include "userdb/userdb.h"
#include "webfused/log/log.h"
#include <webfuse/credentials.h>
#include <stdlib.h>
#include <string.h>
struct wfd_file_authenticator
{
char * filename;
};
static void
wfd_file_authenticator_dispose(
void * data)
{
struct wfd_file_authenticator * authenticator = data;
free(authenticator->filename);
free(authenticator);
}
static bool
wfd_file_authenticator_authenticate(
struct wf_credentials const * credentials,
void * user_data)
{
bool result = false;
struct wfd_file_authenticator * authenticator = user_data;
char const * username = wf_credentials_get(credentials, "username");
char const * password = wf_credentials_get(credentials, "password");
if ((NULL != username) && (NULL != password))
{
struct userdb * db = userdb_create("");
result = userdb_load_file(db, authenticator->filename);
if (result)
{
result = userdb_check(db, username, password);
}
userdb_dispose(db);
}
WFD_INFO("authenticate user \'%s\': %s",
(NULL != username) ? username : "<unknown>",
result ? "success" : "failure");
return result;
}
static char const *
wfd_file_authenticator_get_type(
void * data)
{
(void) data;
return "username";
}
static struct wfd_authenticator_vtable const
wfd_file_authenticator_vtable =
{
.dispose = &wfd_file_authenticator_dispose,
.authenticate = &wfd_file_authenticator_authenticate,
.get_type = &wfd_file_authenticator_get_type
};
bool
wfd_file_authenticator_create(
struct wfd_settings * settings,
struct wfd_authenticator * authenticator)
{
bool result = false;
char const * filename = wfd_settings_get_string(settings, "file");
if (NULL != filename)
{
struct wfd_file_authenticator * data = malloc(sizeof(struct wfd_file_authenticator));
data->filename = strdup(filename);
authenticator->vtable = &wfd_file_authenticator_vtable;
authenticator->data = data;
result = true;
}
return result;
}

View File

@ -0,0 +1,26 @@
#ifndef WFD_AUTH_FILE_AUTHENTICATOR_H
#define WFD_AUTH_FILE_AUTHENTICATOR_H
#ifndef __cplusplus
#include <stdbool.h>
#endif
#ifdef __cplusplus
extern "C"
{
#endif
struct wfd_authenticator;
struct wfd_settings;
extern bool
wfd_file_authenticator_create(
struct wfd_settings * settings,
struct wfd_authenticator * authenticator);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,174 @@
#include "webfused/auth/pam_authenticator.h"
#include "webfused/auth/authenticator.h"
#include "webfused/config/settings.h"
#include "webfused/log/log.h"
#include <webfuse/credentials.h>
#include <security/pam_appl.h>
#include <stdlib.h>
#include <string.h>
struct wfd_pam_authenticator
{
char * service_name;
};
struct wfd_pam_credentials
{
char const * username;
char const * password;
};
static int
wfd_pam_conversation(
int count,
struct pam_message const ** messages,
struct pam_response * * ret_responses,
void * user_data)
{
int result = PAM_SUCCESS;
struct pam_response * responses = malloc(count * sizeof(struct pam_response));
struct wfd_pam_credentials * creds = user_data;
for(int i = 0; (PAM_SUCCESS == result) && (i < count); i++)
{
struct pam_response * response = &responses[i];
struct pam_message const * message = messages[i];
response->resp_retcode = 0;
response->resp = NULL;
switch (message->msg_style)
{
case PAM_PROMPT_ECHO_ON:
response->resp = strdup(creds->username);
break;
case PAM_PROMPT_ECHO_OFF:
response->resp = strdup(creds->password);
break;
default:
free(responses);
result = PAM_CONV_ERR;
}
}
if (PAM_SUCCESS == result)
{
*ret_responses = responses;
}
return result;
}
static void
wfd_pam_authenticator_dispose(
void * data)
{
struct wfd_pam_authenticator * authenticator = data;
free(authenticator->service_name);
free(authenticator);
}
static bool
wfd_pam_authenticator_authenticate(
struct wf_credentials const * credentials,
void * user_data)
{
bool result = false;
struct wfd_pam_authenticator * authenticator = user_data;
char const * username = wf_credentials_get(credentials, "username");
char const * password = wf_credentials_get(credentials, "password");
if ((NULL != username) && (NULL != password))
{
struct wfd_pam_credentials creds =
{
.username = username,
.password = password
};
struct pam_conv const conversation =
{
.conv = &wfd_pam_conversation,
.appdata_ptr = &creds
};
pam_handle_t * handle = NULL;
bool cleanup_handle = false;
result = true;
{
int rc = pam_start(authenticator->service_name, NULL,
&conversation, &handle);
result = (PAM_SUCCESS == rc);
cleanup_handle = result;
if (!result)
{
WFD_ERROR("failed to start pam conversation: %s", pam_strerror(handle, rc));
}
}
if (result)
{
int rc = pam_authenticate(handle, PAM_DISALLOW_NULL_AUTHTOK);
result = (PAM_SUCCESS == rc);
if (!result)
{
WFD_INFO("failed to authenticate user \'%s\' (pam_authenticate): %s",
username, pam_strerror(handle, rc));
}
}
if (result)
{
int rc = pam_acct_mgmt(handle, PAM_DISALLOW_NULL_AUTHTOK);
result = (PAM_SUCCESS == rc);
if (!result)
{
WFD_INFO("failed to authenticate user \'%s\' (pam_acct_mgmt): %s",
username, pam_strerror(handle, rc));
}
}
if (cleanup_handle)
{
pam_end(handle, 0);
}
}
WFD_INFO("authenticate user \'%s\': %s",
(NULL != username) ? username : "<unknown>",
result ? "success" : "failure");
return result;
}
static char const *
wfd_pam_authenticator_get_type(
void * data)
{
(void) data;
return "username";
}
static struct wfd_authenticator_vtable const
wfd_pam_authenticator_vtable =
{
.dispose = &wfd_pam_authenticator_dispose,
.authenticate = &wfd_pam_authenticator_authenticate,
.get_type = &wfd_pam_authenticator_get_type
};
bool
wfd_pam_authenticator_create(
struct wfd_settings * settings,
struct wfd_authenticator * authenticator)
{
struct wfd_pam_authenticator * data = malloc(sizeof(struct wfd_pam_authenticator));
data->service_name = strdup(wfd_settings_get_string_or_default(settings, "service_name", "webfused"));
authenticator->vtable = &wfd_pam_authenticator_vtable;
authenticator->data = data;
return true;
}

View File

@ -0,0 +1,25 @@
#ifndef WFD_AUTH_PAM_AUTHENTICATOR_H
#define WFD_AUTH_PAM_AUTHENTICATOR_H
#ifndef __cplusplus
#include <stdbool.h>
#endif
#ifdef __cplusplus
extern "C"
{
#endif
struct wfd_authenticator;
struct wfd_settings;
extern bool
wfd_pam_authenticator_create(
struct wfd_settings * settings,
struct wfd_authenticator * authenticator);
#ifdef __cplusplus
}
#endif
#endif

116
src/webfused/change_user.c Normal file
View File

@ -0,0 +1,116 @@
#include "webfused/change_user.h"
#include "webfused/log/log.h"
#include <unistd.h>
#include <sys/types.h>
#include <grp.h>
#include <pwd.h>
#include <errno.h>
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
static bool
wfd_switch_group(
char const * group_name)
{
struct group * group = getgrnam(group_name);
bool result = (NULL != group);
if (!result)
{
WFD_ERROR("failed to switch group: unknown group \'%s\'", group_name);
}
if (result)
{
result = (0 != group->gr_gid);
if (!result)
{
WFD_ERROR("failed to switch group: switch to root (gid 0) is not allowed");
}
}
if (result)
{
result = (0 == setgid(group->gr_gid));
if (!result)
{
WFD_ERROR("failed to set group id: %s", strerror(errno));
}
}
if (result)
{
result = (0 == setgroups(0, NULL));
if (!result)
{
WFD_ERROR("failed to release supplemenatary groups (setgroups): %s", strerror(errno));
}
}
return result;
}
static bool
wfd_switch_user(
char const * user_name)
{
struct passwd * user = getpwnam(user_name);
bool result = (NULL != user);
if (!result)
{
WFD_ERROR("failed to switch user: unknown user \'%s\'", user_name);
}
if (result)
{
result = (0 != user->pw_uid);
if (!result)
{
WFD_ERROR("failed to switch user: switch to root (uid 0) is not allowed");
}
}
if (result)
{
result = (0 == setuid(user->pw_uid));
if (!result)
{
WFD_ERROR("failed to switch user (setuid): %s", strerror(errno));
}
}
return result;
}
bool
wfd_change_user(
char const * user,
char const * group)
{
bool result = true;
bool const is_root = (0 == getuid());
if (is_root)
{
result = ((NULL != user) && (NULL != group));
if (!result)
{
WFD_ERROR("webfuse daemon cannot be run as root: specify user and group in config");
}
if (result)
{
result = wfd_switch_group(group);
}
if (result)
{
result = wfd_switch_user(user);
}
}
return result;
}

View File

@ -0,0 +1,22 @@
#ifndef WFD_CHANGE_USER_H
#define WFD_CHANGE_USER_H
#ifndef __cplusplus
#include <stdbool.h>
#endif
#ifdef __cplusplus
extern "C"
{
#endif
extern bool
wfd_change_user(
char const * user,
char const * group);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,177 @@
#include "webfused/config/config.h"
#include "webfused/config/config_intern.h"
#include "webfused/auth/factory.h"
#include "webfused/auth/authenticator.h"
#include "webfused/mountpoint_factory.h"
#include "webfused/log/manager.h"
#include <webfuse/server_config.h>
#include <stdlib.h>
#include <string.h>
#define WFD_CONFIG_DEFAULT_PORT (8080)
#define WFD_CONFIG_DEFAULT_VHOSTNAME ("localhost")
struct wfd_config
{
struct wf_server_config * server;
bool has_authenticator;
struct wfd_authenticator authenticator;
struct wfd_mountpoint_factory * mountpoint_factory;
char * user;
char * group;
};
struct wfd_config *
wfd_config_create(void)
{
struct wfd_config * config = malloc(sizeof(struct wfd_config));
config->mountpoint_factory = wfd_mountpoint_factory_create();
config->has_authenticator = false;
config->server = wf_server_config_create();
wf_server_config_set_vhostname(config->server, WFD_CONFIG_DEFAULT_VHOSTNAME);
wf_server_config_set_port(config->server, WFD_CONFIG_DEFAULT_PORT);
wf_server_config_set_mountpoint_factory(config->server,
wfd_mountpoint_factory_create_mountpoint,
config->mountpoint_factory);
config->user = NULL;
config->group = NULL;
return config;
}
void
wfd_config_dispose(
struct wfd_config * config)
{
wf_server_config_dispose(config->server);
if (config->has_authenticator)
{
wfd_authenticator_dispose(config->authenticator);
}
wfd_mountpoint_factory_dispose(config->mountpoint_factory);
free(config->user);
free(config->group);
free(config);
}
void
wfd_config_set_server_vhostname(
struct wfd_config * config,
char const * vhost_name)
{
wf_server_config_set_vhostname(config->server, vhost_name);
}
void
wfd_config_set_server_port(
struct wfd_config * config,
int port)
{
wf_server_config_set_port(config->server, port);
}
void
wfd_config_set_server_key(
struct wfd_config * config,
char const * key_path)
{
wf_server_config_set_keypath(config->server, key_path);
}
void
wfd_config_set_server_cert(
struct wfd_config * config,
char const * cert_path)
{
wf_server_config_set_certpath(config->server, cert_path);
}
void
wfd_config_set_server_document_root(
struct wfd_config * config,
char const * document_root)
{
wf_server_config_set_documentroot(config->server, document_root);
}
bool
wfd_config_add_auth_provider(
struct wfd_config * config,
char const * provider,
struct wfd_settings * settings)
{
bool result = false;
if (!config->has_authenticator)
{
result = wfd_authenticator_create(provider, settings, &config->authenticator);
if (result)
{
wf_server_config_add_authenticator(
config->server,
wfd_authenticator_get_type(config->authenticator),
config->authenticator.vtable->authenticate,
config->authenticator.data);
config->has_authenticator = true;
}
}
return result;
}
bool
wfd_config_add_filesystem(
struct wfd_config * config,
char const * name,
char const * mount_point,
struct wfd_string_list const * mount_options)
{
return wfd_mountpoint_factory_add_filesystem(
config->mountpoint_factory, name, mount_point, mount_options);
}
bool
wfd_config_set_logger(
struct wfd_config * config,
char const * provider,
int level,
struct wfd_settings * settings)
{
return wfd_log_manager_set_logger(provider, level, settings);
}
void
wfd_config_set_user(
struct wfd_config * config,
char const * user,
char const * group)
{
config->user = strdup(user);
config->group = strdup(group);
}
struct wf_server_config *
wfd_config_get_server_config(
struct wfd_config * config)
{
return config->server;
}
char const *
wfd_config_get_user(
struct wfd_config * config)
{
return config->user;
}
char const *
wfd_config_get_group(
struct wfd_config * config)
{
return config->group;
}

View File

@ -0,0 +1,45 @@
#ifndef WFD_CONFIG_H
#define WFD_CONFIG_H
#ifndef __cplusplus
#include <stdbool.h>
#include <stddef.h>
#else
#include <cstddef>
#endif
#ifdef __cplusplus
extern "C"
{
#endif
#define WFD_CONFIG_VERSION_MAJOR 1
#define WFD_CONFIG_VERSION_MINOR 1
#define WFD_CONFIG_VERSION_STR_MAJOR "1"
#define WFD_CONFIG_VERSION_STR_MINOR "1"
struct wfd_config;
struct wf_server_config;
extern void
wfd_config_dispose(
struct wfd_config * config);
extern struct wf_server_config *
wfd_config_get_server_config(
struct wfd_config * config);
extern char const *
wfd_config_get_user(
struct wfd_config * config);
extern char const *
wfd_config_get_group(
struct wfd_config * config);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,75 @@
#ifndef WFD_CONFIG_INTERN_H
#define WFD_CONFIG_INTERN_H
#ifndef __cplusplus
#include <stdbool.h>
#endif
#ifdef __cplusplus
extern "C"
{
#endif
struct wfd_settings;
struct wfd_config;
struct wfd_string_list;
extern struct wfd_config *
wfd_config_create(void);
extern void
wfd_config_set_server_vhostname(
struct wfd_config * config,
char const * vhost_name);
extern void
wfd_config_set_server_port(
struct wfd_config * config,
int port);
extern void
wfd_config_set_server_key(
struct wfd_config * config,
char const * key_path);
extern void
wfd_config_set_server_cert(
struct wfd_config * config,
char const * cert_path);
extern void
wfd_config_set_server_document_root(
struct wfd_config * config,
char const * document_root);
extern bool
wfd_config_add_auth_provider(
struct wfd_config * config,
char const * provider,
struct wfd_settings * settings);
extern bool
wfd_config_add_filesystem(
struct wfd_config * config,
char const * name,
char const * mount_point,
struct wfd_string_list const * mount_options);
extern bool
wfd_config_set_logger(
struct wfd_config * config,
char const * provider,
int level,
struct wfd_settings * settings);
extern void
wfd_config_set_user(
struct wfd_config * config,
char const * user,
char const * group);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,407 @@
#include "webfused/config/factory.h"
#include "webfused/config/config_intern.h"
#include "webfused/config/config.h"
#include "webfused/config/settings_intern.h"
#include "webfused/log/log.h"
#include "webfused/util/string_list.h"
#include <libconfig.h>
#include <stdlib.h>
#include <stdbool.h>
#if ((LIBCONFIG_VER_MAJOR != 1) || (LIBCONFIG_VER_MINOR < 5))
#error "libconfig 1.5 or higher needed"
#endif
static bool
wfd_config_check_version(
config_t * config)
{
int version_major;
int rc = config_lookup_int(config, "version.major", &version_major);
if (CONFIG_TRUE != rc)
{
WFD_ERROR("failed to load config: missing version.major");
return false;
}
if (WFD_CONFIG_VERSION_MAJOR != version_major)
{
WFD_ERROR("failed to load config: "
"incompatible versions: expected %d, but war %d",
WFD_CONFIG_VERSION_MAJOR, version_major);
return false;
}
int version_minor;
rc = config_lookup_int(config, "version.minor", &version_minor);
if (CONFIG_TRUE != rc)
{
WFD_ERROR("failed to load config: missing version.minor");
return false;
}
if (WFD_CONFIG_VERSION_MINOR < version_minor)
{
WFD_WARN("newer config detected: some features might be disabled");
}
else if (WFD_CONFIG_VERSION_MINOR > version_minor)
{
WFD_INFO("old config detected: some features might use default values");
}
return true;
}
static bool
wfd_config_read_logger(
config_t * config,
struct wfd_config * builder)
{
bool result = true;
bool hasLogger = (NULL != config_lookup(config, "log"));
if (hasLogger)
{
char const * provider;
int rc = config_lookup_string(config, "log.provider", &provider);
if (CONFIG_TRUE != rc)
{
WFD_ERROR("failed to load config: missing log provider");
result = false;
}
char const * level_str;
if (result)
{
rc = config_lookup_string(config, "log.level", &level_str);
if (CONFIG_TRUE != rc)
{
WFD_ERROR("failed to load config: missing log level");
result = false;
}
}
int level;
if (result)
{
bool success = wfd_log_level_parse(level_str, &level);
if (!success)
{
WFD_ERROR("failed to parse log level: unknown value \'%s\'", level_str);
result = false;
}
}
if (result)
{
config_setting_t * setting = config_lookup(config, "log.settings");
struct wfd_settings settings;
wfd_settings_init(&settings, setting);
result = wfd_config_set_logger(builder, provider, level, &settings);
wfd_settings_cleanup(&settings);
}
}
return result;
}
static void
wfd_config_read_server(
config_t * config,
struct wfd_config * builder)
{
char const * vhost_name;
int rc = config_lookup_string(config, "server.vhost_name", &vhost_name);
if (CONFIG_TRUE == rc)
{
wfd_config_set_server_vhostname(builder, vhost_name);
}
int port;
rc = config_lookup_int(config, "server.port", &port);
if (CONFIG_TRUE == rc)
{
wfd_config_set_server_port(builder, port);
}
char const * cert;
rc = config_lookup_string(config, "server.tls.certificate", &cert);
if (CONFIG_TRUE == rc)
{
wfd_config_set_server_cert(builder, cert);
}
char const * key;
rc = config_lookup_string(config, "server.tls.key", &key);
if (CONFIG_TRUE == rc)
{
wfd_config_set_server_key(builder, key);
}
char const * doc_root;
rc = config_lookup_string(config, "server.document_root", &doc_root);
if (CONFIG_TRUE == rc)
{
wfd_config_set_server_document_root(builder, doc_root);
}
}
static bool
wfd_config_read_authenticator(
config_setting_t * authenticator,
struct wfd_config * builder)
{
bool result = (NULL != authenticator);
if (!result)
{
WFD_ERROR("failed to load config: invalid authentication section");
}
char const * provider_name = NULL;
if (result)
{
int rc = config_setting_lookup_string(authenticator, "provider", &provider_name);
if (CONFIG_TRUE != rc)
{
WFD_ERROR("failed to load config: missing authentication provider");
result = false;
}
}
struct config_setting_t * settings = NULL;
if (result)
{
settings = config_setting_lookup(authenticator, "settings");
if (NULL == settings)
{
WFD_ERROR("failed to load config: missing authentication settings");
result = false;
}
}
if (result)
{
struct wfd_settings auth_settings;
wfd_settings_init(&auth_settings, settings);
result = wfd_config_add_auth_provider(builder, provider_name, &auth_settings);
wfd_settings_cleanup(&auth_settings);
}
return result;
}
static bool
wfd_config_read_authentication(
config_t * config,
struct wfd_config * builder)
{
bool result = true;
config_setting_t * authentication = config_lookup(config, "authentication");
if (NULL != authentication)
{
int length = config_setting_length(authentication);
for (int i = 0; (result) && (i < length); i++)
{
config_setting_t * authenticator = config_setting_get_elem(authentication, i);
result = wfd_config_read_authenticator(authenticator, builder);
}
}
return result;
}
static void
wfd_config_read_mountoptions(
config_setting_t * filesystem,
struct wfd_string_list * mount_options)
{
config_setting_t * list = config_setting_get_member(filesystem, "mount_options");
if ((NULL != list) && (CONFIG_TRUE == config_setting_is_list(list)))
{
int length = config_setting_length(list);
for (int i = 0; i < length; i++)
{
char const * option = config_setting_get_string_elem(list, i);
if (NULL != option)
{
wfd_string_list_add(mount_options, option);
}
}
}
}
static bool
wfd_config_read_filesystems(
config_t * config,
struct wfd_config * builder)
{
bool result = true;
config_setting_t * filesystems = config_lookup(config, "filesystems");
if (NULL != filesystems)
{
int length = config_setting_length(filesystems);
for (int i = 0; i < length; i++)
{
config_setting_t * fs = config_setting_get_elem(filesystems, i);
if (NULL == fs)
{
WFD_ERROR("failed to load config: invalid filesystem section");
result = false;
break;
}
char const * name;
int rc = config_setting_lookup_string(fs, "name", &name);
if (rc != CONFIG_TRUE)
{
WFD_ERROR("failed to load config: missing required filesystem property \'name\'");
result = false;
break;
}
char const * mount_point;
rc = config_setting_lookup_string(fs, "mount_point", &mount_point);
if (rc != CONFIG_TRUE)
{
WFD_ERROR("failed to load config: missing required filesystem property \'mount_point\'");
result = false;
break;
}
struct wfd_string_list mount_options;
wfd_string_list_init(&mount_options);
wfd_config_read_mountoptions(fs, &mount_options);
result = wfd_config_add_filesystem(builder, name, mount_point, &mount_options);
wfd_string_list_cleanup(&mount_options);
if (!result)
{
break;
}
}
}
return result;
}
static bool
wfd_config_read_user(
config_t * config,
struct wfd_config * builder)
{
bool result = true;
bool has_user = (NULL != config_lookup(config, "user"));
if (has_user)
{
char const * user;
{
int rc = config_lookup_string(config, "user.name", &user);
if (CONFIG_TRUE != rc)
{
WFD_ERROR("failed to load config: missing required user propert: \'name\'");
result = false;
}
}
char const * group;
if (result)
{
int rc = config_lookup_string(config, "user.group", &group);
if (CONFIG_TRUE != rc)
{
WFD_ERROR("failed to load config: missing required user propert: \'group\'");
result = false;
}
}
if (result)
{
wfd_config_set_user(builder, user, group);
}
}
return result;
}
static struct wfd_config *
wfd_config_load(
config_t * config)
{
struct wfd_config * result = wfd_config_create();
bool success = wfd_config_check_version(config)
&& wfd_config_read_logger(config, result)
&& wfd_config_read_authentication(config, result)
&& wfd_config_read_filesystems(config, result)
&& wfd_config_read_user(config, result)
;
if (success)
{
wfd_config_read_server(config, result);
}
if (!success)
{
wfd_config_dispose(result);
result = NULL;
}
return result;
}
struct wfd_config *
wfd_config_load_file(
char const * filename)
{
struct wfd_config * result = NULL;
config_t config;
config_init(&config);
int rc = config_read_file(&config, filename);
if (CONFIG_TRUE == rc)
{
result = wfd_config_load(&config);
}
else
{
WFD_ERROR("failed to load config: %s: %d: %s",
config_error_file(&config),
config_error_line(&config),
config_error_text(&config));
}
config_destroy(&config);
return result;
}
struct wfd_config *
wfd_config_load_string(
char const * contents)
{
struct wfd_config * result = NULL;
config_t config;
config_init(&config);
int rc = config_read_string(&config, contents);
if (CONFIG_TRUE == rc)
{
result = wfd_config_load(&config);
}
else
{
WFD_ERROR("failed to load config: %d: %s",
config_error_line(&config),
config_error_text(&config));
}
config_destroy(&config);
return result;
}

View File

@ -0,0 +1,23 @@
#ifndef WFD_CONFIG_FACTORY_H
#define WFD_CONFIG_FACTORY_H
#ifdef __cplusplus
extern "C"
{
#endif
struct wfd_config;
extern struct wfd_config *
wfd_config_load_file(
char const * filename);
extern struct wfd_config *
wfd_config_load_string(
char const * contents);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,60 @@
#include "webfused/config/settings.h"
#include "webfused/config/settings_intern.h"
#include <libconfig.h>
#include <stddef.h>
void
wfd_settings_init(
struct wfd_settings * settings,
struct config_setting_t * setting)
{
settings->setting = setting;
}
void
wfd_settings_cleanup(
struct wfd_settings * settings)
{
settings->setting = NULL;
}
char const *
wfd_settings_get_string(
struct wfd_settings * settings,
char const * key)
{
if (NULL == settings) {return NULL; }
char const * result;
int rc = config_setting_lookup_string(settings->setting, key, &result);
return (CONFIG_TRUE == rc) ? result : NULL;
}
char const *
wfd_settings_get_string_or_default(
struct wfd_settings * settings,
char const * key,
char const * default_value)
{
if (NULL == settings) {return default_value; }
char const * result;
int rc = config_setting_lookup_string(settings->setting, key, &result);
return (CONFIG_TRUE == rc) ? result : default_value;
}
bool
wfd_settings_get_bool(
struct wfd_settings * settings,
char const * key)
{
if (NULL == settings) {return false; }
int result;
int rc = config_setting_lookup_bool(settings->setting, key, &result);
return ((CONFIG_TRUE == rc) && (CONFIG_TRUE == result));
}

View File

@ -0,0 +1,37 @@
#ifndef WFD_CONFIG_SETTINGS_H
#define WFD_CONFIG_SETTINGS_H
#ifndef __cplusplus
#include <stdbool.h>
#endif
#ifdef __cplusplus
extern "C"
{
#endif
struct wfd_settings;
extern char const *
wfd_settings_get_string(
struct wfd_settings * settings,
char const * key);
extern char const *
wfd_settings_get_string_or_default(
struct wfd_settings * settings,
char const * key,
char const * default_value);
extern bool
wfd_settings_get_bool(
struct wfd_settings * settings,
char const * key);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,30 @@
#ifndef WFD_CONFIG_SETTINGS_INTERN_H
#define WFD_CONFIG_SETTINGS_INTERN_H
#ifdef __cplusplus
extern "C"
{
#endif
struct config_setting_t;
struct wfd_settings
{
struct config_setting_t * setting;
};
extern void
wfd_settings_init(
struct wfd_settings * settings,
struct config_setting_t * setting);
extern void
wfd_settings_cleanup(
struct wfd_settings * settings);
#ifdef __cplusplus
}
#endif
#endif

163
src/webfused/daemon.c Normal file
View File

@ -0,0 +1,163 @@
#include "webfused/daemon.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#include <stdbool.h>
#include <signal.h>
#include <unistd.h>
#include <getopt.h>
#include <webfuse/webfuse.h>
#include "webfused/config/config.h"
#include "webfused/config/factory.h"
#include "webfused/log/log.h"
#include "webfused/log/logger.h"
#include "webfused/log/stderr_logger.h"
#include "webfused/change_user.h"
#define WFD_SERVICE_TIMEOUT (1 * 1000)
#define WFD_DEFAULT_CONFIG_FILE ("/etc/webfused.conf")
struct args
{
char * config_file;
bool show_help;
};
static bool shutdown_requested = false;
static void show_help(void)
{
printf(
"webfused, Copyright (c) 2019-2020, webfused authors <https://github.com/falk-werner/webfused>\n"
"Websocket file system daemon\n"
"\n"
"Usage: webfused [-f <config file>] | -h\n"
"\n"
"Options:\n"
"\t-f, --config-file Path to config file (default: /etc/webfuse.conf)\n"
"\t-h, --help Print this message and terminate\n"
"\n");
}
static int parse_arguments(int argc, char * argv[], struct args * args)
{
static struct option const options[] =
{
{"config-file", required_argument, NULL, 'f'},
{"help", no_argument, NULL, 'h'},
{NULL, 0, NULL, 0}
};
args->config_file = strdup(WFD_DEFAULT_CONFIG_FILE);
args->show_help = false;
bool result = EXIT_SUCCESS;
bool finished = false;
optind = 0;
while ((!finished) && (EXIT_SUCCESS == result))
{
int option_index = 0;
int const c = getopt_long(argc, argv, "f:h", options, &option_index);
switch (c)
{
case -1:
finished = true;
break;
case 'h':
args->show_help = true;
finished = true;
break;
case 'f':
free(args->config_file);
args->config_file = strdup(optarg);
break;
default:
fprintf(stderr, "error: unknown argument\n");
result = EXIT_FAILURE;
break;
}
}
if (EXIT_SUCCESS != result)
{
args->show_help = true;
}
return result;
}
static void on_interrupt(int signal_id)
{
(void) signal_id;
shutdown_requested = true;
}
int wfd_daemon_run(int argc, char * argv[])
{
wfd_stderr_logger_init(WFD_LOGLEVEL_ALL, NULL);
struct args args;
int result = parse_arguments(argc, argv, &args);
if (!args.show_help)
{
signal(SIGINT, on_interrupt);
struct wfd_config * config = wfd_config_load_file(args.config_file);
bool success = (NULL != config);
if (!success)
{
fprintf(stderr, "fatal: failed to load server config\n");
result = EXIT_FAILURE;
}
if (success)
{
success = wfd_change_user(
wfd_config_get_user(config),
wfd_config_get_group(config));
}
if (success)
{
struct wf_server_config * server_config = wfd_config_get_server_config(config);
struct wf_server * server = wf_server_create(server_config);
if (NULL != server)
{
while (!shutdown_requested)
{
wf_server_service(server);
}
wf_server_dispose(server);
}
else
{
fprintf(stderr, "fatal: unable start server\n");
result = EXIT_FAILURE;
}
}
if (NULL != config)
{
wfd_config_dispose(config);
}
}
else
{
show_help();
}
wfd_logger_close();
free(args.config_file);
shutdown_requested = false;
return result;
}

15
src/webfused/daemon.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef WFD_DAEMON_H
#define WFD_DAEMON_H
#ifdef __cplusplus
extern "C"
{
#endif
extern int wfd_daemon_run(int argc, char * argv[]);
#ifdef __cplusplus
}
#endif
#endif

62
src/webfused/log/log.c Normal file
View File

@ -0,0 +1,62 @@
#include "webfused/log/log.h"
#include <strings.h>
char const *
wfd_log_level_tostring(int level)
{
switch (level)
{
case WFD_LOGLEVEL_NONE: return "none";
case WFD_LOGLEVEL_FATAL: return "fatal";
case WFD_LOGLEVEL_ERROR: return "error";
case WFD_LOGLEVEL_WARN: return "warn";
case WFD_LOGLEVEL_INFO: return "info";
case WFD_LOGLEVEL_DEBUG: return "debug";
case WFD_LOGLEVEL_ALL: return "all";
default: return "<unknown>";
}
}
bool
wfd_log_level_parse(
char const * level,
int * result)
{
bool success = true;
if (0 == strcasecmp("all", level))
{
*result = WFD_LOGLEVEL_ALL;
}
else if (0 == strcasecmp("none", level))
{
*result = WFD_LOGLEVEL_NONE;
}
else if (0 == strcasecmp("fatal", level))
{
*result = WFD_LOGLEVEL_FATAL;
}
else if (0 == strcasecmp("error", level))
{
*result = WFD_LOGLEVEL_ERROR;
}
else if ((0 == strcasecmp("warn", level)) ||
(0 == strcasecmp("warning", level)))
{
*result = WFD_LOGLEVEL_WARN;
}
else if (0 == strcasecmp("info", level))
{
*result = WFD_LOGLEVEL_INFO;
}
else if (0 == strcasecmp("debug", level))
{
*result = WFD_LOGLEVEL_DEBUG;
}
else
{
return false;
}
return success;
}

68
src/webfused/log/log.h Normal file
View File

@ -0,0 +1,68 @@
#ifndef WFD_LOG_H
#define WFD_LOG_H
#ifndef __cplusplus
#include <stdbool.h>
#include <stdarg.h>
#else
#include <cstdarg>
#endif
#ifdef __cplusplus
extern "C"
{
#endif
#ifndef WFD_LOGLEVEL
#define WFD_LOGLEVEL WFD_LOGLEVEL_ALL
#endif
#define WFD_LOGLEVEL_NONE -1
#define WFD_LOGLEVEL_FATAL 1
#define WFD_LOGLEVEL_ERROR 3
#define WFD_LOGLEVEL_WARN 4
#define WFD_LOGLEVEL_INFO 5
#define WFD_LOGLEVEL_DEBUG 7
#define WFD_LOGLEVEL_ALL 8
#define WFD_FATAL(...) \
WFD_LOG(WFD_LOGLEVEL_FATAL, __VA_ARGS__)
#define WFD_ERROR(...) \
WFD_LOG(WFD_LOGLEVEL_ERROR, __VA_ARGS__)
#define WFD_WARN(...) \
WFD_LOG(WFD_LOGLEVEL_WARN, __VA_ARGS__)
#define WFD_INFO(...) \
WFD_LOG(WFD_LOGLEVEL_INFO, __VA_ARGS__)
#define WFD_DEBUG(...) \
WFD_LOG(WFD_LOGLEVEL_DEBUG, __VA_ARGS__)
#define WFD_LOG(level, ...) \
do { \
if (WFD_LOGLEVEL >= (level)) { \
wfd_log((level), __VA_ARGS__); \
} \
} while (0)
extern void
wfd_log(
int level,
char const * format,
...);
extern char const *
wfd_log_level_tostring(int level);
extern bool
wfd_log_level_parse(
char const * level,
int * result);
#ifdef __cplusplus
}
#endif
#endif

86
src/webfused/log/logger.c Normal file
View File

@ -0,0 +1,86 @@
#include "webfused/log/logger.h"
#include "webfused/log/log.h"
#include <stddef.h>
struct wfd_logger
{
int level;
wfd_logger_log_fn * log;
wfd_logger_onclose_fn * onclose;
void * user_data;
};
static void wfd_logger_default_log(
void * user_data,
int level,
char const * format,
va_list args);
static struct wfd_logger g_wfd_logger =
{
.level = WFD_LOGLEVEL_ALL,
.log = &wfd_logger_default_log,
.onclose = NULL,
.user_data = NULL
};
void
wfd_logger_init(
int level,
wfd_logger_log_fn * log,
wfd_logger_onclose_fn * onclose,
void * user_data)
{
wfd_logger_close();
g_wfd_logger.level = level;
g_wfd_logger.log = log;
g_wfd_logger.onclose = onclose;
g_wfd_logger.user_data = user_data;
}
void
wfd_logger_close(void)
{
if (NULL != g_wfd_logger.onclose)
{
g_wfd_logger.onclose(g_wfd_logger.user_data);
}
g_wfd_logger.level = WFD_LOGLEVEL_ALL;
g_wfd_logger.log = &wfd_logger_default_log;
g_wfd_logger.onclose = NULL;
g_wfd_logger.user_data = NULL;
}
void
wfd_log(
int level,
char const * format,
...)
{
if (g_wfd_logger.level >= level)
{
va_list args;
va_start(args, format);
g_wfd_logger.log(
g_wfd_logger.user_data,
level,
format,
args);
va_end(args);
}
}
static void wfd_logger_default_log(
void * user_data,
int level,
char const * format,
va_list args)
{
(void) user_data;
(void) level;
(void) format;
(void) args;
}

40
src/webfused/log/logger.h Normal file
View File

@ -0,0 +1,40 @@
#ifndef WFD_LOGGER_H
#define WFD_LOGGER_H
#ifndef __cplusplus
#include <stdarg.h>
#else
#include <cstdarg>
#endif
#ifdef __cplusplus
extern "C"
{
#endif
typedef void
wfd_logger_log_fn(
void * user_data,
int level,
char const * format,
va_list args);
typedef void
wfd_logger_onclose_fn(
void * user_data);
extern void
wfd_logger_init(
int level,
wfd_logger_log_fn * log,
wfd_logger_onclose_fn * onclose,
void * user_data);
extern void
wfd_logger_close(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,30 @@
#include "webfused/log/manager.h"
#include "webfused/log/log.h"
#include "webfused/log/stderr_logger.h"
#include "webfused/log/syslog_logger.h"
#include <string.h>
bool
wfd_log_manager_set_logger(
char const * provider,
int level,
struct wfd_settings * settings)
{
bool result = false;
if (0 == strcmp("syslog", provider))
{
result = wfd_syslog_logger_init(level, settings);
}
else if (0 == strcmp("stderr", provider))
{
result = wfd_stderr_logger_init(level, settings);
}
else
{
WFD_ERROR("failed to init log: unknown provider \'%s\'", provider);
}
return result;
}

View File

@ -0,0 +1,25 @@
#ifndef WFD_LOG_MANAGER_H
#define WFD_LOG_MANAGER_H
#ifndef __cplusplus
#include <stdbool.h>
#endif
#ifdef __cplusplus
extern "C"
{
#endif
struct wfd_settings;
extern bool
wfd_log_manager_set_logger(
char const * provider,
int level,
struct wfd_settings * settings);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,29 @@
#include "webfused/log/stderr_logger.h"
#include "webfused/log/logger.h"
#include "webfused/log/log.h"
#include <stdio.h>
#include <stdlib.h>
static void
wfd_stderr_logger_log(
void * user_data,
int level,
char const * format,
va_list args)
{
fprintf(stderr, "%s: ", wfd_log_level_tostring(level));
vfprintf(stderr, format, args);
fprintf(stderr, "\n");
}
bool
wfd_stderr_logger_init(
int level,
struct wfd_settings * settings)
{
(void) settings;
wfd_logger_init(level, &wfd_stderr_logger_log, NULL, NULL);
return true;
}

View File

@ -0,0 +1,24 @@
#ifndef WFD_LOG_STDERR_LOGGER_H
#define WFD_LOG_STDERR_LOGGER_H
#ifndef __cplusplus
#include <stdbool.h>
#endif
#ifdef __cplusplus
extern "C"
{
#endif
struct wfd_settings;
extern bool
wfd_stderr_logger_init(
int level,
struct wfd_settings * settings);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,126 @@
#include "webfused/log/syslog_logger.h"
#include "webfused/log/logger.h"
#include "webfused/log/log.h"
#include "webfused/config/settings.h"
#include <syslog.h>
#include <strings.h>
#include <string.h>
#include <stdlib.h>
#include <stddef.h>
static int
wfd_syslog_logger_to_priority(
int level)
{
switch (level)
{
case WFD_LOGLEVEL_FATAL: return LOG_CRIT;
case WFD_LOGLEVEL_ERROR: return LOG_ERR;
case WFD_LOGLEVEL_WARN: return LOG_WARNING;
case WFD_LOGLEVEL_INFO: return LOG_INFO;
case WFD_LOGLEVEL_DEBUG: return LOG_DEBUG;
default: return LOG_NOTICE;
}
}
static void
wfd_syslog_logger_log(
void * user_data,
int level,
char const * format,
va_list args)
{
(void) user_data;
int prio = wfd_syslog_logger_to_priority(level);
vsyslog(prio, format, args);
}
static void
wfd_syslog_logger_close(
void * user_data)
{
closelog();
free(user_data);
}
struct wfd_syslog_facility
{
char const * name;
int value;
};
static bool
wfd_syslog_logger_parse_facility(
char const * facility,
int * result)
{
static struct wfd_syslog_facility const facilities[] =
{
{"auth", LOG_AUTH},
{"authpriv", LOG_AUTHPRIV},
{"cron", LOG_CRON},
{"daemon", LOG_DAEMON},
{"fpt", LOG_FTP},
{"kern", LOG_KERN},
{"local0", LOG_LOCAL0},
{"local1", LOG_LOCAL1},
{"local2", LOG_LOCAL2},
{"local3", LOG_LOCAL3},
{"local4", LOG_LOCAL4},
{"local5", LOG_LOCAL5},
{"local6", LOG_LOCAL6},
{"local7", LOG_LOCAL7},
{"lpr", LOG_LPR},
{"mail", LOG_MAIL},
{"news", LOG_NEWS},
{"syslog", LOG_SYSLOG},
{"user", LOG_USER},
{"uucp", LOG_UUCP}
};
static size_t const facilites_count = sizeof(facilities) / sizeof(facilities[0]);
for (size_t i = 0; i < facilites_count; i++)
{
if (0 == strcasecmp(facility, facilities[i].name))
{
*result = facilities[i].value;
return true;
}
}
return false;
}
bool
wfd_syslog_logger_init(
int level,
struct wfd_settings * settings)
{
char * ident = strdup(wfd_settings_get_string_or_default(settings, "ident", "webfused"));
char const * facility_str = wfd_settings_get_string_or_default(settings, "facility", "daemon");
bool log_pid = wfd_settings_get_bool(settings, "log_pid");
int facility;
bool result = wfd_syslog_logger_parse_facility(facility_str, &facility);
if (result)
{
int options = (log_pid) ? LOG_PID : 0;
wfd_logger_init(level,
&wfd_syslog_logger_log,
&wfd_syslog_logger_close,
ident);
openlog(ident, options, facility);
}
else
{
free(ident);
WFD_ERROR("failed to init syslog logger: invalid log facility: \'%s\'", facility_str);
}
return result;
}

View File

@ -0,0 +1,24 @@
#ifndef WFD_LOG_SYSLOG_LOGGER_H
#define WFD_LOG_SYSLOG_LOGGER_H
#ifndef __cplusplus
#include <stdbool.h>
#endif
#ifdef __cplusplus
extern "C"
{
#endif
struct wfd_settings;
extern bool
wfd_syslog_logger_init(
int level,
struct wfd_settings * settings);
#ifdef __cplusplus
}
#endif
#endif

6
src/webfused/main.c Normal file
View File

@ -0,0 +1,6 @@
#include "webfused/daemon.h"
int main(int argc, char * argv[])
{
return wfd_daemon_run(argc, argv);
}

View File

@ -0,0 +1,155 @@
#include "webfused/mountpoint_factory.h"
#include "webfused/util/string_list.h"
#include "webfused/log/log.h"
#include <webfuse/mountpoint.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <string.h>
#define WFD_FILESYSTEM_DEFAULT_CAPACITY 16
struct wfd_filesystem
{
char * name;
char * mount_point;
struct wfd_string_list mount_options;
bool in_use;
};
struct wfd_mountpoint_factory
{
struct wfd_filesystem * filesystems;
size_t capacity;
size_t count;
};
static struct wfd_filesystem *
wfd_mountpoint_factory_find(
struct wfd_mountpoint_factory * factory,
char const * name)
{
for (size_t i = 0; i < factory->count; i++)
{
struct wfd_filesystem * filesystem = &(factory->filesystems[i]);
if (0 == strcmp(name, filesystem->name))
{
return filesystem;
}
}
return NULL;
}
static void
wfd_mountpoint_factory_release_mountpoint(
void * user_data)
{
bool * in_use = user_data;
*in_use = false;
}
struct wfd_mountpoint_factory *
wfd_mountpoint_factory_create(void)
{
struct wfd_mountpoint_factory * factory = malloc(sizeof(struct wfd_mountpoint_factory));
factory->filesystems = malloc(sizeof(struct wfd_filesystem) * WFD_FILESYSTEM_DEFAULT_CAPACITY);
factory->count = 0;
factory->capacity = WFD_FILESYSTEM_DEFAULT_CAPACITY;
return factory;
}
void
wfd_mountpoint_factory_dispose(
struct wfd_mountpoint_factory * factory)
{
for(size_t i = 0; i < factory->count; i++)
{
struct wfd_filesystem * filesystem = &(factory->filesystems[i]);
free(filesystem->name);
free(filesystem->mount_point);
wfd_string_list_cleanup(&filesystem->mount_options);
}
free(factory->filesystems);
free(factory);
}
bool
wfd_mountpoint_factory_add_filesystem(
struct wfd_mountpoint_factory * factory,
char const * name,
char const * mount_point,
struct wfd_string_list const * mount_options)
{
bool result = (NULL == wfd_mountpoint_factory_find(factory, name));
if (!result)
{
WFD_ERROR("mount_point already defined: \'%s\'", mount_point);
}
char * path = NULL;
if (result)
{
mkdir(mount_point, 0755);
path = realpath(mount_point, NULL);
if (NULL == path)
{
WFD_ERROR("invalid mount_point: \'%s\'", mount_point);
result = false;
}
}
if (result)
{
if (factory->count >= factory->capacity)
{
factory->capacity *= 2;
factory->filesystems = realloc(factory->filesystems,
sizeof(struct wfd_filesystem) * factory->capacity);
}
struct wfd_filesystem * actual = &(factory->filesystems[factory->count]);
actual->name = strdup(name);
actual->mount_point = path;
wfd_string_list_init_copy(&actual->mount_options, mount_options);
actual->in_use = false;
factory->count++;
}
return result;
}
extern struct wf_mountpoint *
wfd_mountpoint_factory_create_mountpoint(
char const * filesystem,
void * user_data)
{
struct wfd_mountpoint_factory * factory = user_data;
struct wfd_filesystem * fs = wfd_mountpoint_factory_find(factory, filesystem);
if (NULL == fs)
{
WFD_INFO("failed to create mountpoint: filesystem \'%s\' not found", filesystem);
return NULL;
}
if (fs->in_use)
{
WFD_INFO("failed to create mountpoint: filesystem \'%s\' already in use", filesystem);
return NULL;
}
fs->in_use = true;
struct wf_mountpoint * result = wf_mountpoint_create(fs->mount_point);
wf_mountpoint_set_userdata(result,
&fs->in_use, &wfd_mountpoint_factory_release_mountpoint);
for (size_t i = 0; i < fs->mount_options.size; i++)
{
wf_mountpoint_add_mountoption(result, fs->mount_options.items[i]);
}
WFD_INFO("created mountpoint \'%s\' at path \'%s\'", filesystem, fs->mount_point);
return result;
}

View File

@ -0,0 +1,41 @@
#ifndef WFD_MOUNTPOINT_FACTORY_H
#define WFD_MOUNTPOINT_FACTORY_H
#include "webfuse/mountpoint_factory.h"
#ifndef __cplusplus
#include <stdbool.h>
#endif
#ifdef __cplusplus
extern "C"
{
#endif
struct wfd_mountpoint_factory;
struct wfd_string_list;
extern struct wfd_mountpoint_factory *
wfd_mountpoint_factory_create(void);
extern void
wfd_mountpoint_factory_dispose(
struct wfd_mountpoint_factory * factory);
extern bool
wfd_mountpoint_factory_add_filesystem(
struct wfd_mountpoint_factory * factory,
char const * name,
char const * mount_point,
struct wfd_string_list const * mount_options);
extern struct wf_mountpoint *
wfd_mountpoint_factory_create_mountpoint(
char const * filesystem,
void * user_data);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,62 @@
#include "webfused/util/string_list.h"
#include <stdlib.h>
#include <string.h>
#define WFD_STRING_LIST_INITIAL_CAPACITY 8
void
wfd_string_list_init(
struct wfd_string_list * list)
{
list->size = 0;
list->capacity = WFD_STRING_LIST_INITIAL_CAPACITY;
list->items = malloc(sizeof(char *) * list->capacity);
}
void
wfd_string_list_init_copy(
struct wfd_string_list * list,
struct wfd_string_list const * other)
{
if (0 < other->size)
{
list->size = other->size;
list->capacity = other->capacity;
list->items = malloc(sizeof(char *) * list->capacity);
for(size_t i = 0; i < other->size; i++)
{
list->items[i] = strdup(other->items[i]);
}
}
else
{
wfd_string_list_init(list);
}
}
void
wfd_string_list_cleanup(
struct wfd_string_list * list)
{
for (size_t i = 0; i < list->size; i++)
{
free(list->items[i]);
}
free(list->items);
}
void
wfd_string_list_add(
struct wfd_string_list * list,
char const * item)
{
if (list->size >= list->capacity)
{
list->capacity *= 2;
list->items = realloc(list->items, sizeof(char *) * list->capacity);
}
list->items[list->size] = strdup(item);
list->size++;
}

View File

@ -0,0 +1,44 @@
#ifndef WFD_UTIL_STRING_LIST_H
#define WFD_UTIL_STRING_LIST_H
#ifndef __cplusplus
#include <stddef.h>
#else
#include <cstddef>
#endif
#ifdef __cplusplus
extern "C"
{
#endif
struct wfd_string_list
{
size_t size;
size_t capacity;
char * * items;
};
extern void
wfd_string_list_init(
struct wfd_string_list * list);
extern void
wfd_string_list_init_copy(
struct wfd_string_list * list,
struct wfd_string_list const * other);
extern void
wfd_string_list_cleanup(
struct wfd_string_list * list);
extern void
wfd_string_list_add(
struct wfd_string_list * list,
char const * item);
#ifdef __cplusplus
}
#endif
#endif

20
test/auth/factory.cc Normal file
View File

@ -0,0 +1,20 @@
#include <gtest/gtest.h>
#include "webfused/auth/factory.h"
#include "webfused/auth/authenticator.h"
#include "webfused/log/log.h"
#include "mock/logger.hpp"
using ::testing::_;
using ::webfused_test::MockLogger;
TEST(auth_factory, fail_unknown_provider)
{
MockLogger logger;
EXPECT_CALL(logger, log(WFD_LOGLEVEL_ERROR, _, _)).Times(1);
EXPECT_CALL(logger, onclose()).Times(1);
wfd_authenticator authenticator;
bool result = wfd_authenticator_create("unknown", NULL, &authenticator);
ASSERT_FALSE(result);
}

View File

@ -0,0 +1,159 @@
#include "webfused/auth/file_authenticator.h"
#include "webfused/auth/authenticator.h"
#include "webfused/config/settings.h"
#include "webfused/auth/factory.h"
#include "mock/credentials.hpp"
#include "mock/settings.hpp"
#include <gtest/gtest.h>
#include <libconfig.h>
using ::webfused_test::MockSettings;
using ::webfused_test::MockCredentials;
using ::testing::Return;
using ::testing::StrEq;
using ::testing::_;
TEST(file_authenticator, create)
{
MockSettings settings;
EXPECT_CALL(settings, wfd_settings_get_string(_,StrEq("file"))).Times(1).WillOnce(Return("test_passwd.json"));
wfd_authenticator authenticator;
bool success = wfd_file_authenticator_create(nullptr, &authenticator);
ASSERT_TRUE(success);
wfd_authenticator_dispose(authenticator);
}
TEST(file_authenticator, create_fail_missing_file)
{
MockSettings settings;
EXPECT_CALL(settings, wfd_settings_get_string(_,StrEq("file"))).Times(1).WillOnce(Return(nullptr));
wfd_authenticator authenticator;
bool success = wfd_file_authenticator_create(nullptr, &authenticator);
ASSERT_FALSE(success);
}
TEST(file_authenticator, create_via_factory)
{
MockSettings settings;
EXPECT_CALL(settings, wfd_settings_get_string(_,StrEq("file"))).Times(1).WillOnce(Return("test_passwd.json"));
wfd_authenticator authenticator;
bool success = wfd_authenticator_create("file", nullptr, &authenticator);
ASSERT_TRUE(success);
wfd_authenticator_dispose(authenticator);
}
TEST(file_authenticator, authenticate)
{
MockSettings settings;
EXPECT_CALL(settings, wfd_settings_get_string(_,StrEq("file"))).Times(1).WillOnce(Return("test_passwd.json"));
wfd_authenticator authenticator;
bool success = wfd_file_authenticator_create(nullptr, &authenticator);
ASSERT_TRUE(success);
MockCredentials creds;
EXPECT_CALL(creds, wf_credentials_get(_,StrEq("username"))).Times(1).WillOnce(Return("bob"));
EXPECT_CALL(creds, wf_credentials_get(_,StrEq("password"))).Times(1).WillOnce(Return("secret"));
bool is_authenticated = wfd_authenticator_authenticate(authenticator, nullptr);
ASSERT_TRUE(is_authenticated);
wfd_authenticator_dispose(authenticator);
}
TEST(file_authenticator, authenticate_fail_wrong_passwd)
{
MockSettings settings;
EXPECT_CALL(settings, wfd_settings_get_string(_,StrEq("file"))).Times(1).WillOnce(Return("test_passwd.json"));
wfd_authenticator authenticator;
bool success = wfd_file_authenticator_create(nullptr, &authenticator);
ASSERT_TRUE(success);
MockCredentials creds;
EXPECT_CALL(creds, wf_credentials_get(_,StrEq("username"))).Times(1).WillOnce(Return("bob"));
EXPECT_CALL(creds, wf_credentials_get(_,StrEq("password"))).Times(1).WillOnce(Return("unkown"));
bool is_authenticated = wfd_authenticator_authenticate(authenticator, nullptr);
ASSERT_FALSE(is_authenticated);
wfd_authenticator_dispose(authenticator);
}
TEST(file_authenticator, authenticate_fail_no_passwd_file)
{
MockSettings settings;
EXPECT_CALL(settings, wfd_settings_get_string(_,StrEq("file"))).Times(1).WillOnce(Return("unknown_passwd.json"));
wfd_authenticator authenticator;
bool success = wfd_file_authenticator_create(nullptr, &authenticator);
ASSERT_TRUE(success);
MockCredentials creds;
EXPECT_CALL(creds, wf_credentials_get(_,StrEq("username"))).Times(1).WillOnce(Return("bob"));
EXPECT_CALL(creds, wf_credentials_get(_,StrEq("password"))).Times(1).WillOnce(Return("secred"));
bool is_authenticated = wfd_authenticator_authenticate(authenticator, nullptr);
ASSERT_FALSE(is_authenticated);
wfd_authenticator_dispose(authenticator);
}
TEST(file_authenticator, authenticate_fail_missing_username)
{
MockSettings settings;
EXPECT_CALL(settings, wfd_settings_get_string(_,StrEq("file"))).Times(1).WillOnce(Return("test_passwd.json"));
wfd_authenticator authenticator;
bool success = wfd_file_authenticator_create(nullptr, &authenticator);
ASSERT_TRUE(success);
MockCredentials creds;
EXPECT_CALL(creds, wf_credentials_get(_,StrEq("username"))).Times(1).WillOnce(Return(nullptr));
EXPECT_CALL(creds, wf_credentials_get(_,StrEq("password"))).Times(1).WillOnce(Return("unkown"));
bool is_authenticated = wfd_authenticator_authenticate(authenticator, nullptr);
ASSERT_FALSE(is_authenticated);
wfd_authenticator_dispose(authenticator);
}
TEST(file_authenticator, authenticate_fail_missing_password)
{
MockSettings settings;
EXPECT_CALL(settings, wfd_settings_get_string(_,StrEq("file"))).Times(1).WillOnce(Return("test_passwd.json"));
wfd_authenticator authenticator;
bool success = wfd_file_authenticator_create(nullptr, &authenticator);
ASSERT_TRUE(success);
MockCredentials creds;
EXPECT_CALL(creds, wf_credentials_get(_,StrEq("username"))).Times(1).WillOnce(Return("bob"));
EXPECT_CALL(creds, wf_credentials_get(_,StrEq("password"))).Times(1).WillOnce(Return(nullptr));
bool is_authenticated = wfd_authenticator_authenticate(authenticator, nullptr);
ASSERT_FALSE(is_authenticated);
wfd_authenticator_dispose(authenticator);
}
TEST(file_authenticator, get_type)
{
MockSettings settings;
EXPECT_CALL(settings, wfd_settings_get_string(_,StrEq("file"))).Times(1).WillOnce(Return("/any/path"));
wfd_authenticator authenticator;
bool success = wfd_file_authenticator_create(nullptr, &authenticator);
ASSERT_TRUE(success);
ASSERT_STREQ("username", wfd_authenticator_get_type(authenticator));
wfd_authenticator_dispose(authenticator);
}

View File

@ -0,0 +1,279 @@
#include "webfused/auth/pam_authenticator.h"
#include "webfused/auth/authenticator.h"
#include "webfused/config/settings.h"
#include "webfused/auth/factory.h"
#include "mock/credentials.hpp"
#include "mock/settings.hpp"
#include "mock/pam.hpp"
#include <gtest/gtest.h>
using ::webfused_test::MockSettings;
using ::webfused_test::MockCredentials;
using ::webfused_test::MockPam;
using ::testing::_;
using ::testing::Return;
using ::testing::StrEq;
using ::testing::Invoke;
using ::testing::StrictMock;
TEST(pam_authenticator, create)
{
wfd_authenticator authenticator;
bool success = wfd_pam_authenticator_create(nullptr, &authenticator);
ASSERT_TRUE(success);
wfd_authenticator_dispose(authenticator);
}
TEST(pam_authenticator, create_via_factory)
{
wfd_authenticator authenticator;
bool success = wfd_authenticator_create("pam", nullptr, &authenticator);
ASSERT_TRUE(success);
wfd_authenticator_dispose(authenticator);
}
TEST(pam_authenticator, get_type)
{
wfd_authenticator authenticator;
bool success = wfd_pam_authenticator_create(nullptr, &authenticator);
ASSERT_TRUE(success);
ASSERT_STREQ("username", wfd_authenticator_get_type(authenticator));
wfd_authenticator_dispose(authenticator);
}
TEST(pam_authenticator, authenticate)
{
MockPam pam;
EXPECT_CALL(pam, pam_start(StrEq("webfused"), nullptr, _, _)).Times(1).WillOnce(Return(PAM_SUCCESS));
EXPECT_CALL(pam, pam_authenticate(_, PAM_DISALLOW_NULL_AUTHTOK)).Times(1).WillOnce(Return(PAM_SUCCESS));
EXPECT_CALL(pam, pam_acct_mgmt(_, PAM_DISALLOW_NULL_AUTHTOK)).Times(1).WillOnce(Return(PAM_SUCCESS));
EXPECT_CALL(pam, pam_end(_, _)).Times(1).WillOnce(Return(PAM_SUCCESS));
wfd_authenticator authenticator;
bool success = wfd_pam_authenticator_create(nullptr, &authenticator);
ASSERT_TRUE(success);
MockCredentials creds;
EXPECT_CALL(creds, wf_credentials_get(_,StrEq("username"))).Times(1).WillOnce(Return("bob"));
EXPECT_CALL(creds, wf_credentials_get(_,StrEq("password"))).Times(1).WillOnce(Return("secret"));
bool is_authenticated = wfd_authenticator_authenticate(authenticator, nullptr);
ASSERT_TRUE(is_authenticated);
wfd_authenticator_dispose(authenticator);
}
TEST(pam_authenticator, authenticate_with_custom_service_name)
{
MockPam pam;
EXPECT_CALL(pam, pam_start(StrEq("brummni"), nullptr, _, _)).Times(1).WillOnce(Return(PAM_SUCCESS));
EXPECT_CALL(pam, pam_authenticate(_, PAM_DISALLOW_NULL_AUTHTOK)).Times(1).WillOnce(Return(PAM_SUCCESS));
EXPECT_CALL(pam, pam_acct_mgmt(_, PAM_DISALLOW_NULL_AUTHTOK)).Times(1).WillOnce(Return(PAM_SUCCESS));
EXPECT_CALL(pam, pam_end(_, _)).Times(1).WillOnce(Return(PAM_SUCCESS));
MockSettings settings;
EXPECT_CALL(settings, wfd_settings_get_string_or_default(_,StrEq("service_name"), StrEq("webfused")))
.Times(1).WillOnce(Return("brummni"));
wfd_authenticator authenticator;
bool success = wfd_pam_authenticator_create(nullptr, &authenticator);
ASSERT_TRUE(success);
MockCredentials creds;
EXPECT_CALL(creds, wf_credentials_get(_,StrEq("username"))).Times(1).WillOnce(Return("bob"));
EXPECT_CALL(creds, wf_credentials_get(_,StrEq("password"))).Times(1).WillOnce(Return("secret"));
bool is_authenticated = wfd_authenticator_authenticate(authenticator, nullptr);
ASSERT_TRUE(is_authenticated);
wfd_authenticator_dispose(authenticator);
}
namespace
{
int valid_conversation(
char const * service_name,
char const * user,
struct pam_conv const * conv,
pam_handle_t * * handle)
{
(void) service_name;
(void) user;
(void) handle;
pam_message request_username = {PAM_PROMPT_ECHO_ON, "username"};
pam_message request_password = {PAM_PROMPT_ECHO_OFF, "password"};
pam_message const * messages[2] =
{
&request_username,
&request_password
};
pam_response * responses;
int rc = conv->conv(2, messages, &responses, conv->appdata_ptr);
if (PAM_SUCCESS == rc)
{
free(responses[0].resp);
free(responses[1].resp);
free(responses);
}
return rc;
}
}
TEST(pam_authenticator, conversation_with_valid_messages)
{
MockPam pam;
EXPECT_CALL(pam, pam_start(StrEq("webfused"), nullptr, _, _))
.Times(1).WillOnce(Invoke(&valid_conversation));
EXPECT_CALL(pam, pam_authenticate(_, PAM_DISALLOW_NULL_AUTHTOK)).Times(1).WillOnce(Return(PAM_SUCCESS));
EXPECT_CALL(pam, pam_acct_mgmt(_, PAM_DISALLOW_NULL_AUTHTOK)).Times(1).WillOnce(Return(PAM_SUCCESS));
EXPECT_CALL(pam, pam_end(_, _)).Times(1).WillOnce(Return(PAM_SUCCESS));
wfd_authenticator authenticator;
bool success = wfd_pam_authenticator_create(nullptr, &authenticator);
ASSERT_TRUE(success);
MockCredentials creds;
EXPECT_CALL(creds, wf_credentials_get(_,StrEq("username"))).Times(1).WillOnce(Return("bob"));
EXPECT_CALL(creds, wf_credentials_get(_,StrEq("password"))).Times(1).WillOnce(Return("secret"));
bool is_authenticated = wfd_authenticator_authenticate(authenticator, nullptr);
ASSERT_TRUE(is_authenticated);
wfd_authenticator_dispose(authenticator);
}
namespace
{
int invalid_conversation(
char const * service_name,
char const * user,
struct pam_conv const * conv,
pam_handle_t * * handle)
{
(void) service_name;
(void) user;
(void) handle;
pam_message invalid_request = {-1, "invalid"};
pam_message const * messages[2] =
{
&invalid_request
};
pam_response * responses;
int rc = conv->conv(1, messages, &responses, conv->appdata_ptr);
return rc;
}
}
TEST(pam_authenticator, conversation_with_invalid_messages)
{
MockPam pam;
EXPECT_CALL(pam, pam_start(StrEq("webfused"), nullptr, _, _))
.Times(1).WillOnce(Invoke(&invalid_conversation));
wfd_authenticator authenticator;
bool success = wfd_pam_authenticator_create(nullptr, &authenticator);
ASSERT_TRUE(success);
MockCredentials creds;
EXPECT_CALL(creds, wf_credentials_get(_,StrEq("username"))).Times(1).WillOnce(Return("bob"));
EXPECT_CALL(creds, wf_credentials_get(_,StrEq("password"))).Times(1).WillOnce(Return("secret"));
bool is_authenticated = wfd_authenticator_authenticate(authenticator, nullptr);
ASSERT_FALSE(is_authenticated);
wfd_authenticator_dispose(authenticator);
}
TEST(pam_authenticator, authenticate_fail_authenticate)
{
MockPam pam;
EXPECT_CALL(pam, pam_start(StrEq("webfused"), nullptr, _, _)).Times(1).WillOnce(Return(PAM_SUCCESS));
EXPECT_CALL(pam, pam_authenticate(_, PAM_DISALLOW_NULL_AUTHTOK)).Times(1).WillOnce(Return(-1));
EXPECT_CALL(pam, pam_end(_, _)).Times(1).WillOnce(Return(PAM_SUCCESS));
wfd_authenticator authenticator;
bool success = wfd_pam_authenticator_create(nullptr, &authenticator);
ASSERT_TRUE(success);
MockCredentials creds;
EXPECT_CALL(creds, wf_credentials_get(_,StrEq("username"))).Times(1).WillOnce(Return("bob"));
EXPECT_CALL(creds, wf_credentials_get(_,StrEq("password"))).Times(1).WillOnce(Return("secret"));
bool is_authenticated = wfd_authenticator_authenticate(authenticator, nullptr);
ASSERT_FALSE(is_authenticated);
wfd_authenticator_dispose(authenticator);
}
TEST(pam_authenticator, authenticate_fail_acct_mgmt)
{
MockPam pam;
EXPECT_CALL(pam, pam_start(StrEq("webfused"), nullptr, _, _)).Times(1).WillOnce(Return(PAM_SUCCESS));
EXPECT_CALL(pam, pam_authenticate(_, PAM_DISALLOW_NULL_AUTHTOK)).Times(1).WillOnce(Return(PAM_SUCCESS));
EXPECT_CALL(pam, pam_acct_mgmt(_, PAM_DISALLOW_NULL_AUTHTOK)).Times(1).WillOnce(Return(-1));
EXPECT_CALL(pam, pam_end(_, _)).Times(1).WillOnce(Return(PAM_SUCCESS));
wfd_authenticator authenticator;
bool success = wfd_pam_authenticator_create(nullptr, &authenticator);
ASSERT_TRUE(success);
MockCredentials creds;
EXPECT_CALL(creds, wf_credentials_get(_,StrEq("username"))).Times(1).WillOnce(Return("bob"));
EXPECT_CALL(creds, wf_credentials_get(_,StrEq("password"))).Times(1).WillOnce(Return("secret"));
bool is_authenticated = wfd_authenticator_authenticate(authenticator, nullptr);
ASSERT_FALSE(is_authenticated);
wfd_authenticator_dispose(authenticator);
}
TEST(pam_authenticator, authenticate_fail_missing_username)
{
StrictMock<MockPam> pam;
wfd_authenticator authenticator;
bool success = wfd_pam_authenticator_create(nullptr, &authenticator);
ASSERT_TRUE(success);
MockCredentials creds;
EXPECT_CALL(creds, wf_credentials_get(_,StrEq("username"))).Times(1).WillOnce(Return(nullptr));
EXPECT_CALL(creds, wf_credentials_get(_,StrEq("password"))).Times(1).WillOnce(Return("secret"));
bool is_authenticated = wfd_authenticator_authenticate(authenticator, nullptr);
ASSERT_FALSE(is_authenticated);
wfd_authenticator_dispose(authenticator);
}
TEST(pam_authenticator, authenticate_fail_missing_password)
{
StrictMock<MockPam> pam;
wfd_authenticator authenticator;
bool success = wfd_pam_authenticator_create(nullptr, &authenticator);
ASSERT_TRUE(success);
MockCredentials creds;
EXPECT_CALL(creds, wf_credentials_get(_,StrEq("username"))).Times(1).WillOnce(Return("bob"));
EXPECT_CALL(creds, wf_credentials_get(_,StrEq("password"))).Times(1).WillOnce(Return(nullptr));
bool is_authenticated = wfd_authenticator_authenticate(authenticator, nullptr);
ASSERT_FALSE(is_authenticated);
wfd_authenticator_dispose(authenticator);
}

154
test/change_user.cc Normal file
View File

@ -0,0 +1,154 @@
#include "webfused/change_user.h"
#include "mock/linux.hpp"
#include <gtest/gtest.h>
using ::webfused_test::MockLinux;
using ::testing::StrictMock;
using ::testing::Return;
using ::testing::StrEq;
TEST(change_user, nop_id_not_root)
{
StrictMock<MockLinux> sys;
EXPECT_CALL(sys, getuid).Times(1).WillOnce(Return(42));
bool success = wfd_change_user("webfused", "daemons");
ASSERT_TRUE(success);
}
TEST(change_user, change_successfully)
{
struct group group;
group.gr_gid = 23;
struct passwd userinfo;
userinfo.pw_uid = 42;
StrictMock<MockLinux> sys;
EXPECT_CALL(sys, getuid).Times(1).WillOnce(Return(0));
EXPECT_CALL(sys, getgrnam(StrEq("daemons"))).Times(1).WillOnce(Return(&group));
EXPECT_CALL(sys, setgid(23)).Times(1).WillOnce(Return(0));
EXPECT_CALL(sys, setgroups(0, nullptr)).Times(1).WillOnce(Return(0));
EXPECT_CALL(sys, getpwnam("webfused")).Times(1).WillOnce(Return(&userinfo));
EXPECT_CALL(sys, setuid(42)).Times(1).WillOnce(Return(0));
bool success = wfd_change_user("webfused", "daemons");
ASSERT_TRUE(success);
}
TEST(change_user, fail_no_username_or_password)
{
StrictMock<MockLinux> sys;
EXPECT_CALL(sys, getuid).WillRepeatedly(Return(0));
ASSERT_FALSE(wfd_change_user(nullptr, "daemons"));
ASSERT_FALSE(wfd_change_user("webfused", nullptr));
ASSERT_FALSE(wfd_change_user(nullptr, nullptr));
}
TEST(change_user, fail_setuid)
{
struct group group;
group.gr_gid = 23;
struct passwd userinfo;
userinfo.pw_uid = 42;
StrictMock<MockLinux> sys;
EXPECT_CALL(sys, getuid).Times(1).WillOnce(Return(0));
EXPECT_CALL(sys, getgrnam(StrEq("daemons"))).Times(1).WillOnce(Return(&group));
EXPECT_CALL(sys, setgid(23)).Times(1).WillOnce(Return(0));
EXPECT_CALL(sys, setgroups(0, nullptr)).Times(1).WillOnce(Return(0));
EXPECT_CALL(sys, getpwnam("webfused")).Times(1).WillOnce(Return(&userinfo));
EXPECT_CALL(sys, setuid(42)).Times(1).WillOnce(Return(-1));
bool success = wfd_change_user("webfused", "daemons");
ASSERT_FALSE(success);
}
TEST(change_user, fail_getpwnam)
{
struct group group;
group.gr_gid = 23;
StrictMock<MockLinux> sys;
EXPECT_CALL(sys, getuid).Times(1).WillOnce(Return(0));
EXPECT_CALL(sys, getgrnam(StrEq("daemons"))).Times(1).WillOnce(Return(&group));
EXPECT_CALL(sys, setgid(23)).Times(1).WillOnce(Return(0));
EXPECT_CALL(sys, setgroups(0, nullptr)).Times(1).WillOnce(Return(0));
EXPECT_CALL(sys, getpwnam("webfused")).Times(1).WillOnce(Return(nullptr));
bool success = wfd_change_user("webfused", "daemons");
ASSERT_FALSE(success);
}
TEST(change_user, fail_setgroups)
{
struct group group;
group.gr_gid = 23;
StrictMock<MockLinux> sys;
EXPECT_CALL(sys, getuid).Times(1).WillOnce(Return(0));
EXPECT_CALL(sys, getgrnam(StrEq("daemons"))).Times(1).WillOnce(Return(&group));
EXPECT_CALL(sys, setgid(23)).Times(1).WillOnce(Return(0));
EXPECT_CALL(sys, setgroups(0, nullptr)).Times(1).WillOnce(Return(-1));
bool success = wfd_change_user("webfused", "daemons");
ASSERT_FALSE(success);
}
TEST(change_user, fail_setgid)
{
struct group group;
group.gr_gid = 23;
StrictMock<MockLinux> sys;
EXPECT_CALL(sys, getuid).Times(1).WillOnce(Return(0));
EXPECT_CALL(sys, getgrnam(StrEq("daemons"))).Times(1).WillOnce(Return(&group));
EXPECT_CALL(sys, setgid(23)).Times(1).WillOnce(Return(-1));
bool success = wfd_change_user("webfused", "daemons");
ASSERT_FALSE(success);
}
TEST(change_user, fail_getgrpnam)
{
StrictMock<MockLinux> sys;
EXPECT_CALL(sys, getuid).Times(1).WillOnce(Return(0));
EXPECT_CALL(sys, getgrnam(StrEq("daemons"))).Times(1).WillOnce(Return(nullptr));
bool success = wfd_change_user("webfused", "daemons");
ASSERT_FALSE(success);
}
TEST(change_user, fail_switch_to_root)
{
struct group group;
group.gr_gid = 23;
struct passwd userinfo;
userinfo.pw_uid = 0;
StrictMock<MockLinux> sys;
EXPECT_CALL(sys, getuid).Times(1).WillOnce(Return(0));
EXPECT_CALL(sys, getgrnam(StrEq("daemons"))).Times(1).WillOnce(Return(&group));
EXPECT_CALL(sys, setgid(23)).Times(1).WillOnce(Return(0));
EXPECT_CALL(sys, setgroups(0, nullptr)).Times(1).WillOnce(Return(0));
EXPECT_CALL(sys, getpwnam("webfused")).Times(1).WillOnce(Return(&userinfo));
bool success = wfd_change_user("webfused", "daemons");
ASSERT_FALSE(success);
}
TEST(change_user, fail_switch_to_root_group)
{
struct group group;
group.gr_gid = 0;
StrictMock<MockLinux> sys;
EXPECT_CALL(sys, getuid).Times(1).WillOnce(Return(0));
EXPECT_CALL(sys, getgrnam(StrEq("daemons"))).Times(1).WillOnce(Return(&group));
bool success = wfd_change_user("webfused", "daemons");
ASSERT_FALSE(success);
}

110
test/config/config.cc Normal file
View File

@ -0,0 +1,110 @@
#include <gtest/gtest.h>
#include "webfused/config/config.h"
#include "webfused/config/config_intern.h"
#include "mock/settings.hpp"
#include "webfused/log/logger.h"
#include "webfused/log/log.h"
#include "webfused/util/string_list.h"
#include "mock/logger.hpp"
using ::webfused_test::MockLogger;
using ::testing::_;
using ::webfused_test::MockSettings;
using ::testing::Return;
using ::testing::StrEq;
TEST(config, server_config)
{
wfd_config * config = wfd_config_create();
ASSERT_NE(nullptr, config);
wfd_config_set_server_vhostname(config, "localhost");
wfd_config_set_server_port(config, 8443);
wfd_config_set_server_key(config, "/path/to/key.pem");
wfd_config_set_server_cert(config, "/path/to/cert.pem");
wfd_config_set_server_document_root(config, "/var/www");
wf_server_config * server_config = wfd_config_get_server_config(config);
ASSERT_NE(nullptr, server_config);
wfd_config_dispose(config);
}
TEST(config, auth_config)
{
wfd_config * config = wfd_config_create();
ASSERT_NE(nullptr, config);
MockSettings settings;
EXPECT_CALL(settings, wfd_settings_get_string(_,StrEq("file"))).Times(1).WillOnce(Return("/any/path"));
bool success = wfd_config_add_auth_provider(config, "file", nullptr);
ASSERT_TRUE(success);
wfd_config_dispose(config);
}
TEST(config, auth_config_failed_to_add_second_provider)
{
wfd_config * config = wfd_config_create();
ASSERT_NE(nullptr, config);
MockSettings settings;
EXPECT_CALL(settings, wfd_settings_get_string(_,StrEq("file"))).Times(1).WillOnce(Return("/any/path"));
bool success = wfd_config_add_auth_provider(config, "file", nullptr);
ASSERT_TRUE(success);
success = wfd_config_add_auth_provider(config, "file", nullptr);
ASSERT_FALSE(success);
wfd_config_dispose(config);
}
TEST(config, auth_config_failed_to_add_unknown_provider)
{
wfd_config * config = wfd_config_create();
ASSERT_NE(nullptr, config);
bool success = wfd_config_add_auth_provider(config, "unknown", nullptr);
ASSERT_FALSE(success);
wfd_config_dispose(config);
}
TEST(config, add_filesystem)
{
wfd_config * config = wfd_config_create();
ASSERT_NE(nullptr, config);
struct wfd_string_list mount_options = {0, 0, nullptr};
bool success = wfd_config_add_filesystem(config, "test", "/tmp/test", &mount_options);
ASSERT_TRUE(success);
wfd_config_dispose(config);
}
TEST(config, set_logger)
{
wfd_config * config = wfd_config_create();
ASSERT_NE(nullptr, config);
bool success = wfd_config_set_logger(config, "stderr", WFD_LOGLEVEL_ALL, nullptr);
ASSERT_TRUE(success);
wfd_config_dispose(config);
}
TEST(config, do_set_user)
{
wfd_config * config = wfd_config_create();
ASSERT_NE(nullptr, config);
wfd_config_set_user(config, "some.user", "some.group");
ASSERT_STREQ("some.user", wfd_config_get_user(config));
ASSERT_STREQ("some.group", wfd_config_get_group(config));
wfd_config_dispose(config);
}

75
test/config/configfile.cc Normal file
View File

@ -0,0 +1,75 @@
#include <gtest/gtest.h>
#include "webfused/config/config.h"
#include "webfused/config/factory.h"
#include "webfused/log/logger.h"
#include "webfused/log/log.h"
#include "mock/logger.hpp"
#include "mock/config_builder.hpp"
#include "mock/libconfig.hpp"
using ::testing::_;
using ::testing::Return;
using ::testing::StrictMock;
using ::testing::StrEq;
using ::webfused_test::MockLogger;
using ::webfused_test::MockConfigBuilder;
using ::webfused_test::MockLibConfig;
TEST(configfile, is_loadable)
{
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, wfd_config_create).Times(1).WillOnce(Return(builder.getBuilder()));
EXPECT_CALL(builder, wfd_config_set_logger(_,_,_,_)).Times(1).WillOnce(Return(true));
EXPECT_CALL(builder, wfd_config_set_server_vhostname(_,StrEq("localhost"))).Times(1);
EXPECT_CALL(builder, wfd_config_set_server_port(_,8080)).Times(1);
EXPECT_CALL(builder, wfd_config_add_auth_provider(_,_, _)).Times(1).WillOnce(Return(true));
EXPECT_CALL(builder, wfd_config_add_filesystem(_,_,_,_)).Times(1).WillOnce(Return(true));
struct wfd_config * config = wfd_config_load_file("webfused.conf");
ASSERT_NE(nullptr, config);
}
TEST(configfile, minimal_config)
{
MockLogger logger;
EXPECT_CALL(logger, log(_, _, _)).Times(0);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, wfd_config_create).Times(1).WillOnce(Return(builder.getBuilder()));
char const minimal[] = "version = { major = " WFD_CONFIG_VERSION_STR_MAJOR ", minor = " WFD_CONFIG_VERSION_STR_MINOR " }\n";
struct wfd_config * config = wfd_config_load_string(minimal);
ASSERT_NE(nullptr, config);
}
TEST(configfile, invalid_config)
{
MockLogger logger;
EXPECT_CALL(logger, log(WFD_LOGLEVEL_ERROR, _, _)).Times(1);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, wfd_config_create).Times(0);
EXPECT_CALL(builder, wfd_config_dispose(_)).Times(0);
char const syntax_error[] = "version.major = " WFD_CONFIG_VERSION_STR_MAJOR "\n";
wfd_config * config = wfd_config_load_string(syntax_error);
ASSERT_EQ(nullptr, config);
}
TEST(configfile, invalid_config_file)
{
MockLogger logger;
EXPECT_CALL(logger, log(WFD_LOGLEVEL_ERROR, _, _)).Times(1);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, wfd_config_create).Times(0);
EXPECT_CALL(builder, wfd_config_dispose(_)).Times(0);
struct wfd_config * config = wfd_config_load_file("invalid.conf");
ASSERT_EQ(nullptr, config);
}

View File

@ -0,0 +1,139 @@
#include <gtest/gtest.h>
#include "webfused/config/config.h"
#include "webfused/config/factory.h"
#include "webfused/log/logger.h"
#include "webfused/log/log.h"
#include "mock/logger.hpp"
#include "mock/config_builder.hpp"
#include "mock/libconfig.hpp"
using ::testing::_;
using ::testing::Return;
using ::testing::StrictMock;
using ::testing::StrEq;
using ::webfused_test::MockLogger;
using ::webfused_test::MockConfigBuilder;
using ::webfused_test::MockLibConfig;
TEST(config_auth, authentication)
{
MockLogger logger;
EXPECT_CALL(logger, log(_, _, _)).Times(0);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, wfd_config_create).Times(1).WillOnce(Return(builder.getBuilder()));
EXPECT_CALL(builder, wfd_config_add_auth_provider(_,_, _)).Times(1).WillOnce(Return(true));
char const config_text[] =
"version = { major = " WFD_CONFIG_VERSION_STR_MAJOR ", minor = " WFD_CONFIG_VERSION_STR_MINOR " }\n"
"authentication:\n"
"(\n"
" {\n"
" provider = \"test\"\n"
" settings: { }\n"
" }\n"
")\n"
;
struct wfd_config * config = wfd_config_load_string(config_text);
ASSERT_NE(nullptr, config);
}
TEST(config_auth, failed_create_authenticator)
{
MockLogger logger;
EXPECT_CALL(logger, log(_, _, _)).Times(0);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, wfd_config_create).Times(1).WillOnce(Return(builder.getBuilder()));
EXPECT_CALL(builder, wfd_config_dispose(_)).Times(1);
EXPECT_CALL(builder, wfd_config_add_auth_provider(_,_, _)).Times(1).WillOnce(Return(false));
char const config_text[] =
"version = { major = " WFD_CONFIG_VERSION_STR_MAJOR ", minor = " WFD_CONFIG_VERSION_STR_MINOR " }\n"
"authentication:\n"
"(\n"
" {\n"
" provider = \"test\"\n"
" settings: { }\n"
" }\n"
")\n"
;
struct wfd_config * config = wfd_config_load_string(config_text);
ASSERT_EQ(nullptr, config);
}
TEST(config_auth, failed_missing_auth_provider)
{
MockLogger logger;
EXPECT_CALL(logger, log(WFD_LOGLEVEL_ERROR, _, _)).Times(1);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, wfd_config_create).Times(1).WillOnce(Return(builder.getBuilder()));
EXPECT_CALL(builder, wfd_config_dispose(_)).Times(1);
char const config_text[] =
"version = { major = " WFD_CONFIG_VERSION_STR_MAJOR ", minor = " WFD_CONFIG_VERSION_STR_MINOR " }\n"
"authentication:\n"
"(\n"
" {\n"
" settings: { }\n"
" }\n"
")\n"
;
struct wfd_config * config = wfd_config_load_string(config_text);
ASSERT_EQ(nullptr, config);
}
TEST(config_auth, failed_missing_auth_settings)
{
MockLogger logger;
EXPECT_CALL(logger, log(WFD_LOGLEVEL_ERROR, _, _)).Times(1);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, wfd_config_create).Times(1).WillOnce(Return(builder.getBuilder()));
EXPECT_CALL(builder, wfd_config_dispose(_)).Times(1);
char const config_text[] =
"version = { major = " WFD_CONFIG_VERSION_STR_MAJOR ", minor = " WFD_CONFIG_VERSION_STR_MINOR " }\n"
"authentication:\n"
"(\n"
" {\n"
" provider = \"test\"\n"
" }\n"
")\n"
;
struct wfd_config * config = wfd_config_load_string(config_text);
ASSERT_EQ(nullptr, config);
}
TEST(config_auth, failed_auth_settings_get_elem)
{
MockLogger logger;
EXPECT_CALL(logger, log(WFD_LOGLEVEL_ERROR, _, _)).Times(1);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, wfd_config_create).Times(1).WillOnce(Return(builder.getBuilder()));
EXPECT_CALL(builder, wfd_config_dispose(_)).Times(1);
MockLibConfig libconfig;
EXPECT_CALL(libconfig, config_setting_get_elem(_,_)).Times(1).WillOnce(Return(nullptr));
char const config_text[] =
"version = { major = " WFD_CONFIG_VERSION_STR_MAJOR ", minor = " WFD_CONFIG_VERSION_STR_MINOR" }\n"
"authentication:\n"
"(\n"
" {\n"
" provider = \"test\"\n"
" settings: { }\n"
" }\n"
")\n"
;
struct wfd_config * config = wfd_config_load_string(config_text);
ASSERT_EQ(nullptr, config);
}

View File

@ -0,0 +1,199 @@
#include <gtest/gtest.h>
#include "webfused/config/config.h"
#include "webfused/config/factory.h"
#include "webfused/util/string_list.h"
#include "webfused/log/logger.h"
#include "webfused/log/log.h"
#include "mock/logger.hpp"
#include "mock/config_builder.hpp"
#include "mock/libconfig.hpp"
using ::testing::Invoke;
using ::testing::_;
using ::testing::Return;
using ::testing::StrictMock;
using ::testing::StrEq;
using ::webfused_test::MockLogger;
using ::webfused_test::MockConfigBuilder;
using ::webfused_test::MockLibConfig;
TEST(configfile_fs, filesystems)
{
MockLogger logger;
EXPECT_CALL(logger, log(_, _, _)).Times(0);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, wfd_config_create).Times(1).WillOnce(Return(builder.getBuilder()));
EXPECT_CALL(builder, wfd_config_add_filesystem(_,_,_,_)).Times(1).WillOnce(Return(true));
char const config_text[] =
"version = { major = " WFD_CONFIG_VERSION_STR_MAJOR ", minor = " WFD_CONFIG_VERSION_STR_MINOR " }\n"
"filesystems:\n"
"(\n"
" {name = \"foo\", mount_point = \"/tmp/test\" }\n"
")\n"
;
struct wfd_config * config = wfd_config_load_string(config_text);
ASSERT_NE(nullptr, config);
}
TEST(configfile_fs, filesystems_empty)
{
MockLogger logger;
EXPECT_CALL(logger, log(_, _, _)).Times(0);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, wfd_config_create).Times(1).WillOnce(Return(builder.getBuilder()));
EXPECT_CALL(builder, wfd_config_add_filesystem(_,_,_,_)).Times(0);
char const config_text[] =
"version = { major = " WFD_CONFIG_VERSION_STR_MAJOR ", minor = " WFD_CONFIG_VERSION_STR_MINOR " }\n"
"filesystems:\n"
"(\n"
")\n"
;
struct wfd_config * config = wfd_config_load_string(config_text);
ASSERT_NE(nullptr, config);
}
TEST(configfile_fs, filesystems_failed_add)
{
MockLogger logger;
EXPECT_CALL(logger, log(_, _, _)).Times(0);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, wfd_config_create).Times(1).WillOnce(Return(builder.getBuilder()));
EXPECT_CALL(builder, wfd_config_dispose(_)).Times(1);
EXPECT_CALL(builder, wfd_config_add_filesystem(_,_,_,_)).Times(1).WillOnce(Return(false));
char const config_text[] =
"version = { major = " WFD_CONFIG_VERSION_STR_MAJOR ", minor = " WFD_CONFIG_VERSION_STR_MINOR " }\n"
"filesystems:\n"
"(\n"
" {name = \"foo\", mount_point = \"/tmp/test\", mount_options = () }\n"
")\n"
;
struct wfd_config * config = wfd_config_load_string(config_text);
ASSERT_EQ(nullptr, config);
}
TEST(configfile_fs, filesystems_failed_missing_name)
{
MockLogger logger;
EXPECT_CALL(logger, log(WFD_LOGLEVEL_ERROR, _, _)).Times(1);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, wfd_config_create).Times(1).WillOnce(Return(builder.getBuilder()));
EXPECT_CALL(builder, wfd_config_dispose(_)).Times(1);
EXPECT_CALL(builder, wfd_config_add_filesystem(_,_,_,_)).Times(0);
char const config_text[] =
"version = { major = " WFD_CONFIG_VERSION_STR_MAJOR ", minor = " WFD_CONFIG_VERSION_STR_MINOR " }\n"
"filesystems:\n"
"(\n"
" {mount_point = \"/tmp/test\" }\n"
")\n"
;
struct wfd_config * config = wfd_config_load_string(config_text);
ASSERT_EQ(nullptr, config);
}
TEST(configfile_fs, filesystems_failed_missing_mountpoint)
{
MockLogger logger;
EXPECT_CALL(logger, log(WFD_LOGLEVEL_ERROR, _, _)).Times(1);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, wfd_config_create).Times(1).WillOnce(Return(builder.getBuilder()));
EXPECT_CALL(builder, wfd_config_dispose(_)).Times(1);
EXPECT_CALL(builder, wfd_config_add_filesystem(_,_,_,_)).Times(0);
char const config_text[] =
"version = { major = " WFD_CONFIG_VERSION_STR_MAJOR ", minor = " WFD_CONFIG_VERSION_STR_MINOR " }\n"
"filesystems:\n"
"(\n"
" {name = \"foo\"}\n"
")\n"
;
struct wfd_config * config = wfd_config_load_string(config_text);
ASSERT_EQ(nullptr, config);
}
TEST(configfile_fs, filesystems_failed_missing_elem)
{
MockLogger logger;
EXPECT_CALL(logger, log(WFD_LOGLEVEL_ERROR, _, _)).Times(1);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, wfd_config_create).Times(1).WillOnce(Return(builder.getBuilder()));
EXPECT_CALL(builder, wfd_config_dispose(_)).Times(1);
EXPECT_CALL(builder, wfd_config_add_filesystem(_,_,_,_)).Times(0);
MockLibConfig libconfig;
EXPECT_CALL(libconfig, config_setting_get_elem(_,_)).Times(1).WillOnce(Return(nullptr));
char const config_text[] =
"version = { major = " WFD_CONFIG_VERSION_STR_MAJOR ", minor = " WFD_CONFIG_VERSION_STR_MINOR " }\n"
"filesystems:\n"
"(\n"
" {name = \"foo\", mount_point = \"/tmp/test\" }\n"
")\n"
;
struct wfd_config * config = wfd_config_load_string(config_text);
ASSERT_EQ(nullptr, config);
}
TEST(configfile_fs, filesystems_failed_add_options)
{
MockLogger logger;
EXPECT_CALL(logger, log(_, _, _)).Times(0);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, wfd_config_create).Times(1).WillOnce(Return(builder.getBuilder()));
EXPECT_CALL(builder, wfd_config_dispose(_)).Times(1);
EXPECT_CALL(builder, wfd_config_add_filesystem(_,_,_,_)).Times(1).WillOnce(Return(false));
char const config_text[] =
"version = { major = " WFD_CONFIG_VERSION_STR_MAJOR ", minor = " WFD_CONFIG_VERSION_STR_MINOR " }\n"
"filesystems:\n"
"(\n"
" {name = \"foo\", mount_point = \"/tmp/test\", mount_options = (\"-o\", \"allow_other\") }\n"
")\n"
;
struct wfd_config * config = wfd_config_load_string(config_text);
ASSERT_EQ(nullptr, config);
}
TEST(configfile_fs, with_mountoptions)
{
MockLogger logger;
EXPECT_CALL(logger, log(_, _, _)).Times(0);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, wfd_config_create).Times(1).WillOnce(Return(builder.getBuilder()));
EXPECT_CALL(builder, wfd_config_add_filesystem(_,_,_,_)).Times(1).WillOnce(Invoke(
[](wfd_config * config, char const * name, char const * mountpoint, wfd_string_list const * mount_options) -> bool {
std::cout << mount_options->items[0] << std::endl;
std::cout << mount_options->items[1] << std::endl;
return (2 == mount_options->size);
}));
char const config_text[] =
"version = { major = " WFD_CONFIG_VERSION_STR_MAJOR ", minor = " WFD_CONFIG_VERSION_STR_MINOR " }\n"
"filesystems:\n"
"(\n"
" {name = \"foo\", mount_point = \"/tmp/test\", mount_options = (\"-o\", \"allow_user\") }\n"
")\n"
;
struct wfd_config * config = wfd_config_load_string(config_text);
ASSERT_NE(nullptr, config);
}

View File

@ -0,0 +1,129 @@
#include <gtest/gtest.h>
#include "webfused/config/config.h"
#include "webfused/config/factory.h"
#include "webfused/log/logger.h"
#include "webfused/log/log.h"
#include "mock/logger.hpp"
#include "mock/config_builder.hpp"
#include "mock/libconfig.hpp"
using ::testing::_;
using ::testing::Return;
using ::testing::StrictMock;
using ::testing::StrEq;
using ::webfused_test::MockLogger;
using ::webfused_test::MockConfigBuilder;
using ::webfused_test::MockLibConfig;
TEST(configfile_log, set_logger)
{
MockLogger logger;
EXPECT_CALL(logger, log(_, _, _)).Times(0);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, wfd_config_create).Times(1).WillOnce(Return(builder.getBuilder()));
EXPECT_CALL(builder, wfd_config_set_logger(_,_, _, _)).Times(1).WillOnce(Return(true));
char const config_text[] =
"version = { major = " WFD_CONFIG_VERSION_STR_MAJOR ", minor = " WFD_CONFIG_VERSION_STR_MINOR " }\n"
"log:\n"
"{\n"
" provider = \"stderr\"\n"
" level = \"all\"\n"
"}\n"
;
struct wfd_config * config = wfd_config_load_string(config_text);
ASSERT_NE(nullptr, config);
}
TEST(configfile_log, log_fail_set_logger)
{
MockLogger logger;
EXPECT_CALL(logger, log(_, _, _)).Times(0);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, wfd_config_create).Times(1).WillOnce(Return(builder.getBuilder()));
EXPECT_CALL(builder, wfd_config_dispose(_)).Times(1);
EXPECT_CALL(builder, wfd_config_set_logger(_,_, _, _)).Times(1).WillOnce(Return(false));
char const config_text[] =
"version = { major = " WFD_CONFIG_VERSION_STR_MAJOR ", minor = " WFD_CONFIG_VERSION_STR_MINOR " }\n"
"log:\n"
"{\n"
" provider = \"stderr\"\n"
" level = \"all\"\n"
"}\n"
;
struct wfd_config * config = wfd_config_load_string(config_text);
ASSERT_EQ(nullptr, config);
}
TEST(configfile_log, log_fail_missing_provider)
{
MockLogger logger;
EXPECT_CALL(logger, log(WFD_LOGLEVEL_ERROR, _, _)).Times(1);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, wfd_config_create).Times(1).WillOnce(Return(builder.getBuilder()));
EXPECT_CALL(builder, wfd_config_dispose(_)).Times(1);
EXPECT_CALL(builder, wfd_config_set_logger(_,_, _, _)).Times(0);
char const config_text[] =
"version = { major = " WFD_CONFIG_VERSION_STR_MAJOR ", minor = " WFD_CONFIG_VERSION_STR_MINOR " }\n"
"log:\n"
"{\n"
" level = \"all\"\n"
"}\n"
;
struct wfd_config * config = wfd_config_load_string(config_text);
ASSERT_EQ(nullptr, config);
}
TEST(configfile_log, log_fail_missing_level)
{
MockLogger logger;
EXPECT_CALL(logger, log(WFD_LOGLEVEL_ERROR, _, _)).Times(1);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, wfd_config_create).Times(1).WillOnce(Return(builder.getBuilder()));
EXPECT_CALL(builder, wfd_config_dispose(_)).Times(1);
EXPECT_CALL(builder, wfd_config_set_logger(_,_, _, _)).Times(0);
char const config_text[] =
"version = { major = " WFD_CONFIG_VERSION_STR_MAJOR ", minor = " WFD_CONFIG_VERSION_STR_MINOR " }\n"
"log:\n"
"{\n"
" provider = \"stderr\"\n"
" level = \"fancy\"\n"
"}\n"
;
struct wfd_config * config = wfd_config_load_string(config_text);
ASSERT_EQ(nullptr, config);
}
TEST(configfile_log, log_fail_invalid_level)
{
MockLogger logger;
EXPECT_CALL(logger, log(WFD_LOGLEVEL_ERROR, _, _)).Times(1);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, wfd_config_create).Times(1).WillOnce(Return(builder.getBuilder()));
EXPECT_CALL(builder, wfd_config_dispose(_)).Times(1);
EXPECT_CALL(builder, wfd_config_set_logger(_, _, _, _)).Times(0);
char const config_text[] =
"version = { major = " WFD_CONFIG_VERSION_STR_MAJOR ", minor = " WFD_CONFIG_VERSION_STR_MINOR " }\n"
"log:\n"
"{\n"
" provider = \"stderr\"\n"
"}\n"
;
struct wfd_config * config = wfd_config_load_string(config_text);
ASSERT_EQ(nullptr, config);
}

View File

@ -0,0 +1,128 @@
#include <gtest/gtest.h>
#include "webfused/config/config.h"
#include "webfused/config/factory.h"
#include "webfused/log/logger.h"
#include "webfused/log/log.h"
#include "mock/logger.hpp"
#include "mock/config_builder.hpp"
#include "mock/libconfig.hpp"
using ::testing::_;
using ::testing::Return;
using ::testing::StrictMock;
using ::testing::StrEq;
using ::webfused_test::MockLogger;
using ::webfused_test::MockConfigBuilder;
using ::webfused_test::MockLibConfig;
TEST(configfile_server, vhost_name)
{
MockLogger logger;
EXPECT_CALL(logger, log(_, _, _)).Times(0);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, wfd_config_create).Times(1).WillOnce(Return(builder.getBuilder()));
EXPECT_CALL(builder, wfd_config_set_server_vhostname(_,StrEq("some.host"))).Times(1);
char const config_text[] =
"version = { major = " WFD_CONFIG_VERSION_STR_MAJOR ", minor = " WFD_CONFIG_VERSION_STR_MINOR " }\n"
"server:\n"
"{\n"
" vhost_name = \"some.host\"\n"
"}\n"
;
struct wfd_config * config = wfd_config_load_string(config_text);
ASSERT_NE(nullptr, config);
}
TEST(configfile_server, port)
{
MockLogger logger;
EXPECT_CALL(logger, log(_, _, _)).Times(0);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, wfd_config_create).Times(1).WillOnce(Return(builder.getBuilder()));
EXPECT_CALL(builder, wfd_config_set_server_port(_,54321)).Times(1);
char const config_text[] =
"version = { major = " WFD_CONFIG_VERSION_STR_MAJOR ", minor = " WFD_CONFIG_VERSION_STR_MINOR " }\n"
"server:\n"
"{\n"
" port = 54321\n"
"}\n"
;
struct wfd_config * config = wfd_config_load_string(config_text);
ASSERT_NE(nullptr, config);
}
TEST(configfile_server, tls_certificate)
{
MockLogger logger;
EXPECT_CALL(logger, log(_, _, _)).Times(0);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, wfd_config_create).Times(1).WillOnce(Return(builder.getBuilder()));
EXPECT_CALL(builder, wfd_config_set_server_cert(_, StrEq("/path/to/cert.pem"))).Times(1);
char const config_text[] =
"version = { major = " WFD_CONFIG_VERSION_STR_MAJOR ", minor = " WFD_CONFIG_VERSION_STR_MINOR " }\n"
"server:\n"
"{\n"
" tls:\n"
" {\n"
" certificate = \"/path/to/cert.pem\"\n"
" }\n"
"}\n"
;
struct wfd_config * config = wfd_config_load_string(config_text);
ASSERT_NE(nullptr, config);
}
TEST(configfile_server, tls_key)
{
MockLogger logger;
EXPECT_CALL(logger, log(_, _, _)).Times(0);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, wfd_config_create).Times(1).WillOnce(Return(builder.getBuilder()));
EXPECT_CALL(builder, wfd_config_set_server_key(_,StrEq("/path/to/key.pem"))).Times(1);
char const config_text[] =
"version = { major = " WFD_CONFIG_VERSION_STR_MAJOR ", minor = " WFD_CONFIG_VERSION_STR_MINOR " }\n"
"server:\n"
"{\n"
" tls:\n"
" {\n"
" key = \"/path/to/key.pem\"\n"
" }\n"
"}\n"
;
struct wfd_config * config = wfd_config_load_string(config_text);
ASSERT_NE(nullptr, config);
}
TEST(configfile_server, document_root)
{
MockLogger logger;
EXPECT_CALL(logger, log(_, _, _)).Times(0);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, wfd_config_create).Times(1).WillOnce(Return(builder.getBuilder()));
EXPECT_CALL(builder, wfd_config_set_server_document_root(_,StrEq("/var/www"))).Times(1);
char const config_text[] =
"version = { major = " WFD_CONFIG_VERSION_STR_MAJOR ", minor = " WFD_CONFIG_VERSION_STR_MINOR " }\n"
"server:\n"
"{\n"
" document_root = \"/var/www\"\n"
"}\n"
;
struct wfd_config * config = wfd_config_load_string(config_text);
ASSERT_NE(nullptr, config);
}

View File

@ -0,0 +1,83 @@
#include <gtest/gtest.h>
#include "webfused/config/config.h"
#include "webfused/config/factory.h"
#include "webfused/log/logger.h"
#include "webfused/log/log.h"
#include "mock/logger.hpp"
#include "mock/config_builder.hpp"
#include "mock/libconfig.hpp"
using ::testing::_;
using ::testing::Return;
using ::testing::StrictMock;
using ::testing::StrEq;
using ::webfused_test::MockLogger;
using ::webfused_test::MockConfigBuilder;
using ::webfused_test::MockLibConfig;
TEST(configfile_user, set_user)
{
MockLogger logger;
EXPECT_CALL(logger, log(_, _, _)).Times(0);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, wfd_config_create).Times(1).WillOnce(Return(builder.getBuilder()));
EXPECT_CALL(builder, wfd_config_set_user(_, _, _)).Times(1);
char const config_text[] =
"version = { major = " WFD_CONFIG_VERSION_STR_MAJOR ", minor = " WFD_CONFIG_VERSION_STR_MINOR " }\n"
"user:\n"
"{\n"
" name = \"webfused\"\n"
" group = \"webfused\"\n"
"}\n"
;
struct wfd_config * config = wfd_config_load_string(config_text);
ASSERT_NE(nullptr, config);
}
TEST(configfile_user, set_user_fail_missing_name)
{
MockLogger logger;
EXPECT_CALL(logger, log(WFD_LOGLEVEL_ERROR, _, _)).Times(1);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, wfd_config_create).Times(1).WillOnce(Return(builder.getBuilder()));
EXPECT_CALL(builder, wfd_config_dispose(_)).Times(1);
EXPECT_CALL(builder, wfd_config_set_user(_, _, _)).Times(0);
char const config_text[] =
"version = { major = " WFD_CONFIG_VERSION_STR_MAJOR ", minor = " WFD_CONFIG_VERSION_STR_MINOR " }\n"
"user:\n"
"{\n"
" group = \"webfused\"\n"
"}\n"
;
struct wfd_config * config = wfd_config_load_string(config_text);
ASSERT_EQ(nullptr, config);
}
TEST(configfile_user, set_user_fail_missing_group)
{
MockLogger logger;
EXPECT_CALL(logger, log(WFD_LOGLEVEL_ERROR, _, _)).Times(1);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, wfd_config_create).Times(1).WillOnce(Return(builder.getBuilder()));
EXPECT_CALL(builder, wfd_config_dispose(_)).Times(1);
EXPECT_CALL(builder, wfd_config_set_user(_, _, _)).Times(0);
char const config_text[] =
"version = { major = " WFD_CONFIG_VERSION_STR_MAJOR ", minor = " WFD_CONFIG_VERSION_STR_MINOR " }\n"
"user:\n"
"{\n"
" name = \"webfused\"\n"
"}\n"
;
struct wfd_config * config = wfd_config_load_string(config_text);
ASSERT_EQ(nullptr, config);
}

View File

@ -0,0 +1,111 @@
#include <gtest/gtest.h>
#include "webfused/config/config.h"
#include "webfused/config/factory.h"
#include "webfused/log/logger.h"
#include "webfused/log/log.h"
#include "mock/logger.hpp"
#include "mock/config_builder.hpp"
#include "mock/libconfig.hpp"
using ::testing::_;
using ::testing::Return;
using ::testing::StrictMock;
using ::testing::StrEq;
using ::webfused_test::MockLogger;
using ::webfused_test::MockConfigBuilder;
using ::webfused_test::MockLibConfig;
TEST(configfile_version, invalid_major_version_too_low)
{
MockLogger logger;
EXPECT_CALL(logger, log(WFD_LOGLEVEL_ERROR, _, _)).Times(1);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, wfd_config_create).Times(1).WillOnce(Return(builder.getBuilder()));
EXPECT_CALL(builder, wfd_config_dispose(_)).Times(1);
char const too_low[] = "version = { major = 0, minor = " WFD_CONFIG_VERSION_STR_MINOR " }\n";
struct wfd_config * config= wfd_config_load_string(too_low);
ASSERT_EQ(nullptr, config);
}
TEST(configfile_version, invalid_major_version_too_high)
{
MockLogger logger;
EXPECT_CALL(logger, log(WFD_LOGLEVEL_ERROR, _, _)).Times(1);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, wfd_config_create).Times(1).WillOnce(Return(builder.getBuilder()));
EXPECT_CALL(builder, wfd_config_dispose(_)).Times(1);
char const too_high[] = "version = { major = 99, minor = " WFD_CONFIG_VERSION_STR_MINOR " }\n";
struct wfd_config * config = wfd_config_load_string(too_high);
ASSERT_EQ(nullptr, config);
}
TEST(configfile_version, invalid_missing_major_version)
{
MockLogger logger;
EXPECT_CALL(logger, log(WFD_LOGLEVEL_ERROR, _, _)).Times(1);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, wfd_config_create).Times(1).WillOnce(Return(builder.getBuilder()));
EXPECT_CALL(builder, wfd_config_dispose(_)).Times(1);
char const too_high[] = "version = { minor = " WFD_CONFIG_VERSION_STR_MINOR " }\n";
struct wfd_config * config = wfd_config_load_string(too_high);
ASSERT_EQ(nullptr, config);
}
TEST(configfile_version, invalid_missing_minor_version)
{
MockLogger logger;
EXPECT_CALL(logger, log(WFD_LOGLEVEL_ERROR, _, _)).Times(1);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, wfd_config_create).Times(1).WillOnce(Return(builder.getBuilder()));
EXPECT_CALL(builder, wfd_config_dispose(_)).Times(1);
char const too_high[] = "version = { major = " WFD_CONFIG_VERSION_STR_MAJOR " }\n";
struct wfd_config * config = wfd_config_load_string(too_high);
ASSERT_EQ(nullptr, config);
}
TEST(configfile_version, valid_older_minor)
{
MockLogger logger;
EXPECT_CALL(logger, log(WFD_LOGLEVEL_INFO, _, _)).Times(1);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, wfd_config_create).Times(1).WillOnce(Return(builder.getBuilder()));
char const valid[] = "version = { major = " WFD_CONFIG_VERSION_STR_MAJOR ", minor = -1 }\n";
struct wfd_config * config = wfd_config_load_string(valid);
ASSERT_NE(nullptr, config);
}
TEST(configfile_version, valid_newer_minor)
{
MockLogger logger;
EXPECT_CALL(logger, log(WFD_LOGLEVEL_WARN, _, _)).Times(1);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, wfd_config_create).Times(1).WillOnce(Return(builder.getBuilder()));
char const valid[] = "version = { major = " WFD_CONFIG_VERSION_STR_MAJOR ", minor = 99 }\n";
struct wfd_config * config = wfd_config_load_string(valid);
ASSERT_NE(nullptr, config);
}

90
test/config/settings.cc Normal file
View File

@ -0,0 +1,90 @@
#include <gtest/gtest.h>
#include "webfused/config/settings_intern.h"
#include "webfused/config/settings.h"
#include <libconfig.h>
TEST(settings, get_string)
{
char const settings_text[] =
"settings:\n"
"{\n"
" string_value = \"some.string\"\n"
" int_value = 42\n"
"}\n"
;
config_t config;
config_init(&config);
int rc = config_read_string(&config, settings_text);
ASSERT_TRUE(CONFIG_TRUE == rc);
config_setting_t * setting = config_lookup(&config, "settings");
ASSERT_NE(nullptr, setting);
wfd_settings settings;
wfd_settings_init(&settings, setting);
ASSERT_STREQ("some.string", wfd_settings_get_string(&settings, "string_value"));
ASSERT_EQ(nullptr, wfd_settings_get_string(&settings, "int_value"));
ASSERT_EQ(nullptr, wfd_settings_get_string(&settings, "invalid_value"));
ASSERT_EQ(nullptr, wfd_settings_get_string(NULL, "invalid_value"));
wfd_settings_cleanup(&settings);
config_destroy(&config);
}
TEST(settings, get_string_or_default)
{
char const settings_text[] =
"settings:\n"
"{\n"
" string_value = \"some.string\"\n"
" int_value = 42\n"
"}\n"
;
config_t config;
config_init(&config);
int rc = config_read_string(&config, settings_text);
ASSERT_TRUE(CONFIG_TRUE == rc);
config_setting_t * setting = config_lookup(&config, "settings");
ASSERT_NE(nullptr, setting);
wfd_settings settings;
wfd_settings_init(&settings, setting);
ASSERT_STREQ("some.string", wfd_settings_get_string_or_default(&settings, "string_value", "default"));
ASSERT_STREQ("default", wfd_settings_get_string_or_default(&settings, "int_value", "default"));
ASSERT_STREQ("default", wfd_settings_get_string_or_default(&settings, "invalid_value", "default"));
ASSERT_STREQ("default", wfd_settings_get_string_or_default(NULL, "invalid_value", "default"));
wfd_settings_cleanup(&settings);
config_destroy(&config);
}
TEST(settings, get_bool)
{
char const settings_text[] =
"settings:\n"
"{\n"
" true_value = true\n"
" false_value = false\n"
" int_value = 42\n"
"}\n"
;
config_t config;
config_init(&config);
int rc = config_read_string(&config, settings_text);
ASSERT_TRUE(CONFIG_TRUE == rc);
config_setting_t * setting = config_lookup(&config, "settings");
ASSERT_NE(nullptr, setting);
wfd_settings settings;
wfd_settings_init(&settings, setting);
ASSERT_TRUE(wfd_settings_get_bool(&settings, "true_value"));
ASSERT_FALSE(wfd_settings_get_bool(&settings, "false_value"));
ASSERT_FALSE(wfd_settings_get_bool(&settings, "int_value"));
ASSERT_FALSE(wfd_settings_get_bool(&settings, "invalid_value"));
ASSERT_FALSE(wfd_settings_get_bool(NULL, "invalid_value"));
wfd_settings_cleanup(&settings);
config_destroy(&config);
}

88
test/daemon.cc Normal file
View File

@ -0,0 +1,88 @@
#include "webfused/daemon.h"
#include "mock/server.hpp"
#include <gtest/gtest.h>
#include <cstdlib>
#include <chrono>
#include <thread>
using ::webfused_test::MockServer;
using ::testing::_;
using ::testing::Return;
TEST(daemon, print_usage)
{
char argv0[] = "daemon";
char argv1[] = "--help";
char * argv[] = { argv0, argv1, NULL};
int exit_code = wfd_daemon_run(2, argv);
ASSERT_EQ(EXIT_SUCCESS, exit_code);
}
TEST(daemon, print_usage_short)
{
char argv0[] = "daemon";
char argv1[] = "-h";
char * argv[] = { argv0, argv1, NULL};
int exit_code = wfd_daemon_run(2, argv);
ASSERT_EQ(EXIT_SUCCESS, exit_code);
}
TEST(daemon, fail_invalid_argument)
{
char argv0[] = "daemon";
char argv1[] = "-x";
char * argv[] = { argv0, argv1, NULL};
int exit_code = wfd_daemon_run(2, argv);
ASSERT_EQ(EXIT_FAILURE, exit_code);
}
TEST(daemon, fail_invalid_config_file)
{
char argv0[] = "daemon";
char argv1[] = "-f";
char argv2[] = "invalid.conf";
char * argv[] = { argv0, argv1, argv2, NULL};
int exit_code = wfd_daemon_run(3, argv);
ASSERT_EQ(EXIT_FAILURE, exit_code);
}
void defered_raise()
{
std::this_thread::sleep_for(std::chrono::milliseconds(50));
raise(SIGINT);
}
TEST(daemon, run)
{
char argv0[] = "daemon";
char argv1[] = "-f";
char argv2[] = "webfused.conf";
char * argv[] = { argv0, argv1, argv2, NULL};
std::thread thread(defered_raise);
int exit_code = wfd_daemon_run(3, argv);
ASSERT_EQ(EXIT_SUCCESS, exit_code);
thread.join();
}
TEST(daemon, run_failed_to_create_server)
{
MockServer server;
EXPECT_CALL(server, wf_server_create(_)).Times(1).WillOnce(Return(nullptr));
char argv0[] = "daemon";
char argv1[] = "-f";
char argv2[] = "webfused.conf";
char * argv[] = { argv0, argv1, argv2, NULL};
int exit_code = wfd_daemon_run(3, argv);
ASSERT_EQ(EXIT_FAILURE, exit_code);
}

4
test/invalid.conf Normal file
View File

@ -0,0 +1,4 @@
# This config file is invalid,
# since "." is not allowed as separator
version.major = 1

170
test/log/log.cc Normal file
View File

@ -0,0 +1,170 @@
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include "webfused/log/logger.h"
#include "webfused/log/log.h"
#include "mock/logger.hpp"
using ::testing::_;
using ::testing::StrEq;
using ::webfused_test::MockLogger;
TEST(log, fatal)
{
MockLogger logger(true);
EXPECT_CALL(logger, log(WFD_LOGLEVEL_FATAL, StrEq("too bad"), _)).Times(1);
EXPECT_CALL(logger, onclose()).Times(1);
wfd_logger_init(WFD_LOGLEVEL_ALL, &wfd_MockLogger_log, &wfd_MockLogger_onclose, logger.getUserData());
WFD_FATAL("too bad");
wfd_logger_close();
}
TEST(log, error)
{
MockLogger logger(true);
EXPECT_CALL(logger, log(WFD_LOGLEVEL_ERROR, StrEq("too bad"), _)).Times(1);
EXPECT_CALL(logger, onclose()).Times(1);
wfd_logger_init(WFD_LOGLEVEL_ALL, &wfd_MockLogger_log, &wfd_MockLogger_onclose, logger.getUserData());
WFD_ERROR("too bad");
wfd_logger_close();
}
TEST(log, warn)
{
MockLogger logger(true);
EXPECT_CALL(logger, log(WFD_LOGLEVEL_WARN, StrEq("too bad"), _)).Times(1);
EXPECT_CALL(logger, onclose()).Times(1);
wfd_logger_init(WFD_LOGLEVEL_ALL, &wfd_MockLogger_log, &wfd_MockLogger_onclose, logger.getUserData());
WFD_WARN("too bad");
wfd_logger_close();
}
TEST(log, info)
{
MockLogger logger(true);
EXPECT_CALL(logger, log(WFD_LOGLEVEL_INFO, StrEq("too bad"), _)).Times(1);
EXPECT_CALL(logger, onclose()).Times(1);
wfd_logger_init(WFD_LOGLEVEL_ALL, &wfd_MockLogger_log, &wfd_MockLogger_onclose, logger.getUserData());
WFD_INFO("too bad");
wfd_logger_close();
}
TEST(log, debug)
{
MockLogger logger(true);
EXPECT_CALL(logger, log(WFD_LOGLEVEL_DEBUG, StrEq("too bad"), _)).Times(1);
EXPECT_CALL(logger, onclose()).Times(1);
wfd_logger_init(WFD_LOGLEVEL_ALL, &wfd_MockLogger_log, &wfd_MockLogger_onclose, logger.getUserData());
WFD_DEBUG("too bad");
wfd_logger_close();
}
TEST(log, respect_loglevel)
{
MockLogger logger(true);
EXPECT_CALL(logger, log(_, _, _)).Times(0);
EXPECT_CALL(logger, onclose()).Times(1);
wfd_logger_init(WFD_LOGLEVEL_WARN, &wfd_MockLogger_log, &wfd_MockLogger_onclose, logger.getUserData());
WFD_DEBUG("too bad");
wfd_logger_close();
}
TEST(log, log_same_loglevel)
{
MockLogger logger(true);
EXPECT_CALL(logger, log(WFD_LOGLEVEL_WARN, StrEq("too bad"), _)).Times(1);
EXPECT_CALL(logger, onclose()).Times(1);
wfd_logger_init(WFD_LOGLEVEL_WARN, &wfd_MockLogger_log, &wfd_MockLogger_onclose, logger.getUserData());
WFD_WARN("too bad");
wfd_logger_close();
}
TEST(log, omit_onclose_if_nullptr)
{
MockLogger logger(true);
EXPECT_CALL(logger, log(WFD_LOGLEVEL_WARN, StrEq("too bad"), _)).Times(1);
EXPECT_CALL(logger, onclose()).Times(0);
wfd_logger_init(WFD_LOGLEVEL_WARN, &wfd_MockLogger_log, nullptr, logger.getUserData());
WFD_WARN("too bad");
wfd_logger_close();
}
TEST(log, default_log)
{
WFD_ERROR("trigger log");
}
TEST(log, loglevel_parse)
{
int level;
ASSERT_TRUE(wfd_log_level_parse("fatal", &level));
ASSERT_EQ(WFD_LOGLEVEL_FATAL, level);
ASSERT_TRUE(wfd_log_level_parse("FATAL", &level));
ASSERT_EQ(WFD_LOGLEVEL_FATAL, level);
ASSERT_TRUE(wfd_log_level_parse("error", &level));
ASSERT_EQ(WFD_LOGLEVEL_ERROR, level);
ASSERT_TRUE(wfd_log_level_parse("ERROR", &level));
ASSERT_EQ(WFD_LOGLEVEL_ERROR, level);
ASSERT_TRUE(wfd_log_level_parse("warn", &level));
ASSERT_EQ(WFD_LOGLEVEL_WARN, level);
ASSERT_TRUE(wfd_log_level_parse("WARN", &level));
ASSERT_EQ(WFD_LOGLEVEL_WARN, level);
ASSERT_TRUE(wfd_log_level_parse("warning", &level));
ASSERT_EQ(WFD_LOGLEVEL_WARN, level);
ASSERT_TRUE(wfd_log_level_parse("WARNING", &level));
ASSERT_EQ(WFD_LOGLEVEL_WARN, level);
ASSERT_TRUE(wfd_log_level_parse("info", &level));
ASSERT_EQ(WFD_LOGLEVEL_INFO, level);
ASSERT_TRUE(wfd_log_level_parse("INFO", &level));
ASSERT_EQ(WFD_LOGLEVEL_INFO, level);
ASSERT_TRUE(wfd_log_level_parse("debug", &level));
ASSERT_EQ(WFD_LOGLEVEL_DEBUG, level);
ASSERT_TRUE(wfd_log_level_parse("DEBUG", &level));
ASSERT_EQ(WFD_LOGLEVEL_DEBUG, level);
ASSERT_FALSE(wfd_log_level_parse("<invalid>", &level));
ASSERT_TRUE(wfd_log_level_parse("all", &level));
ASSERT_EQ(WFD_LOGLEVEL_ALL, level);
ASSERT_TRUE(wfd_log_level_parse("ALL", &level));
ASSERT_EQ(WFD_LOGLEVEL_ALL, level);
ASSERT_TRUE(wfd_log_level_parse("none", &level));
ASSERT_EQ(WFD_LOGLEVEL_NONE, level);
ASSERT_TRUE(wfd_log_level_parse("NONE", &level));
ASSERT_EQ(WFD_LOGLEVEL_NONE, level);
}
TEST(log, log_level_tostring)
{
ASSERT_STREQ("none", wfd_log_level_tostring(WFD_LOGLEVEL_NONE));
ASSERT_STREQ("fatal", wfd_log_level_tostring(WFD_LOGLEVEL_FATAL));
ASSERT_STREQ("error", wfd_log_level_tostring(WFD_LOGLEVEL_ERROR));
ASSERT_STREQ("warn", wfd_log_level_tostring(WFD_LOGLEVEL_WARN));
ASSERT_STREQ("info", wfd_log_level_tostring(WFD_LOGLEVEL_INFO));
ASSERT_STREQ("debug", wfd_log_level_tostring(WFD_LOGLEVEL_DEBUG));
ASSERT_STREQ("all", wfd_log_level_tostring(WFD_LOGLEVEL_ALL));
ASSERT_STREQ("<unknown>", wfd_log_level_tostring(42));
}

10
test/log/log_manager.cc Normal file
View File

@ -0,0 +1,10 @@
#include "webfused/log/manager.h"
#include "webfused/log/log.h"
#include <gtest/gtest.h>
#include <stddef.h>
TEST(log_manager, set_logger_fail_unknown_provider)
{
ASSERT_FALSE(wfd_log_manager_set_logger("unknown", WFD_LOGLEVEL_ALL, NULL));
}

33
test/log/stderr_logger.cc Normal file
View File

@ -0,0 +1,33 @@
#include "webfused/log/stderr_logger.h"
#include "webfused/log/manager.h"
#include "webfused/log/logger.h"
#include "webfused/log/log.h"
#include <gtest/gtest.h>
#include <stddef.h>
TEST(stderr_logger, init)
{
ASSERT_TRUE(wfd_stderr_logger_init(WFD_LOGLEVEL_ALL, NULL));
wfd_logger_close();
}
TEST(stderr_logger, init_via_manager)
{
ASSERT_TRUE(wfd_log_manager_set_logger("stderr", WFD_LOGLEVEL_ALL, NULL));
wfd_logger_close();
}
TEST(stderr_logger, log)
{
ASSERT_TRUE(wfd_stderr_logger_init(WFD_LOGLEVEL_ALL, NULL));
WFD_FATAL("webfused test");
WFD_ERROR("webfused test");
WFD_WARN ("webfused test");
WFD_INFO ("webfused test");
WFD_DEBUG("webfused test");
wfd_log(-1, "webfused test");
wfd_logger_close();
}

51
test/log/syslog_logger.cc Normal file
View File

@ -0,0 +1,51 @@
#include "webfused/log/syslog_logger.h"
#include "webfused/log/manager.h"
#include "webfused/log/logger.h"
#include "webfused/log/log.h"
#include "mock/settings.hpp"
#include <gtest/gtest.h>
#include <stddef.h>
using ::webfused_test::MockSettings;
using ::testing::StrEq;
using ::testing::_;
using ::testing::Return;
TEST(syslog_logger, init)
{
ASSERT_TRUE(wfd_syslog_logger_init(WFD_LOGLEVEL_ALL, NULL));
wfd_logger_close();
}
TEST(syslog_logger, init_fail_invalid_facility)
{
MockSettings settings;
EXPECT_CALL(settings, wfd_settings_get_string_or_default(_,StrEq("ident"), _)).Times(1).WillOnce(Return("webfused_test"));
EXPECT_CALL(settings, wfd_settings_get_string_or_default(_,StrEq("facility"), _)).Times(1).WillOnce(Return("invalid"));
EXPECT_CALL(settings, wfd_settings_get_bool(_,StrEq("log_pid"))).Times(1).WillOnce(Return(false));
wfd_settings * fake_settings = reinterpret_cast<wfd_settings*>(0xDEADBEEF);
ASSERT_FALSE(wfd_syslog_logger_init(WFD_LOGLEVEL_ALL, fake_settings));
}
TEST(syslog_logger, init_via_manager)
{
ASSERT_TRUE(wfd_log_manager_set_logger("syslog", WFD_LOGLEVEL_ALL, NULL));
wfd_logger_close();
}
TEST(syslog_logger, log)
{
ASSERT_TRUE(wfd_syslog_logger_init(WFD_LOGLEVEL_ALL, NULL));
WFD_FATAL("webfused test");
WFD_ERROR("webfused test");
WFD_WARN ("webfused test");
WFD_INFO ("webfused test");
WFD_DEBUG("webfused test");
wfd_log(-1, "webfused test");
wfd_logger_close();
}

View File

@ -0,0 +1,40 @@
#include "mock/config_builder.hpp"
#include "util/wrap.hpp"
extern "C"
{
static webfused_test::IConfigBuilder * wfd_MockConfigBuilder = nullptr;
WFD_WRAP_FUNC0(wfd_MockConfigBuilder, wfd_config *, wfd_config_create);
WFD_WRAP_FUNC1(wfd_MockConfigBuilder, void, wfd_config_dispose, wfd_config *);
WFD_WRAP_FUNC2(wfd_MockConfigBuilder, void, wfd_config_set_server_vhostname, wfd_config *, char const *);
WFD_WRAP_FUNC2(wfd_MockConfigBuilder, void, wfd_config_set_server_port, wfd_config *, int);
WFD_WRAP_FUNC2(wfd_MockConfigBuilder, void, wfd_config_set_server_key, wfd_config *, char const *);
WFD_WRAP_FUNC2(wfd_MockConfigBuilder, void, wfd_config_set_server_cert, wfd_config *, char const *);
WFD_WRAP_FUNC2(wfd_MockConfigBuilder, void, wfd_config_set_server_document_root, wfd_config *, char const *);
WFD_WRAP_FUNC3(wfd_MockConfigBuilder, bool, wfd_config_add_auth_provider, wfd_config *, char const *, wfd_settings *);
WFD_WRAP_FUNC4(wfd_MockConfigBuilder, bool, wfd_config_add_filesystem, wfd_config *, char const *, char const *, wfd_string_list *);
WFD_WRAP_FUNC4(wfd_MockConfigBuilder, bool, wfd_config_set_logger, wfd_config *, char const *, int, wfd_settings *);
WFD_WRAP_FUNC3(wfd_MockConfigBuilder, void, wfd_config_set_user, wfd_config *, char const *, char const *);
}
namespace webfused_test
{
MockConfigBuilder::MockConfigBuilder()
{
wfd_MockConfigBuilder = this;
}
MockConfigBuilder::~MockConfigBuilder()
{
wfd_MockConfigBuilder = nullptr;
}
struct wfd_config * MockConfigBuilder::getBuilder()
{
IConfigBuilder * config_builder = this;
return reinterpret_cast<wfd_config *>(config_builder);
}
}

View File

@ -0,0 +1,49 @@
#ifndef WFD_MOCK_CONFIG_BUILDER_HPP
#define WFD_MOCK_CONFIG_BUILDER_HPP
#include <gmock/gmock.h>
#include "webfused/config/config_intern.h"
namespace webfused_test
{
class IConfigBuilder
{
public:
virtual ~IConfigBuilder() = default;
virtual wfd_config * wfd_config_create(void) = 0;
virtual void wfd_config_dispose(wfd_config * config) = 0;
virtual void wfd_config_set_server_vhostname(wfd_config * config, char const * vhostname) = 0;
virtual void wfd_config_set_server_port(wfd_config * config, int port) = 0;
virtual void wfd_config_set_server_key(wfd_config * config, char const * key_path) = 0;
virtual void wfd_config_set_server_cert(wfd_config * config, char const * cert_path) = 0;
virtual void wfd_config_set_server_document_root(wfd_config * config, char const * document_root) = 0;
virtual bool wfd_config_add_auth_provider(wfd_config * config, char const * provider, wfd_settings * settings) = 0;
virtual bool wfd_config_add_filesystem(wfd_config * config, char const * name, char const * mountpoint, wfd_string_list const * mount_options) = 0;
virtual bool wfd_config_set_logger(wfd_config * config, char const * provider, int level, wfd_settings * settings) = 0;
virtual void wfd_config_set_user(wfd_config * config, char const * user, char const * group) = 0;
};
class MockConfigBuilder: public IConfigBuilder
{
public:
MockConfigBuilder();
~MockConfigBuilder() override;
MOCK_METHOD0(wfd_config_create, wfd_config * (void));
MOCK_METHOD1(wfd_config_dispose, void (wfd_config * config));
MOCK_METHOD2(wfd_config_set_server_vhostname, void (wfd_config * config, char const * vhostname));
MOCK_METHOD2(wfd_config_set_server_port, void (wfd_config * config, int port));
MOCK_METHOD2(wfd_config_set_server_key, void (wfd_config * config, char const * key_path));
MOCK_METHOD2(wfd_config_set_server_cert, void (wfd_config * config, char const * cert_path));
MOCK_METHOD2(wfd_config_set_server_document_root, void (wfd_config * config, char const * document_root));
MOCK_METHOD3(wfd_config_add_auth_provider, bool (wfd_config * config, char const * provider, wfd_settings * settings));
MOCK_METHOD4(wfd_config_add_filesystem, bool (wfd_config * config, char const * name, char const * mountpoint, wfd_string_list const * mount_options));
MOCK_METHOD4(wfd_config_set_logger, bool (wfd_config * config, char const * provider, int level, wfd_settings * settings));
MOCK_METHOD3(wfd_config_set_user, void (wfd_config * config, char const * user, char const * group));
struct wfd_config * getBuilder();
};
}
#endif

26
test/mock/credentials.cc Normal file
View File

@ -0,0 +1,26 @@
#include "mock/credentials.hpp"
#include "util/wrap.hpp"
extern "C"
{
static webfused_test::ICredentials * wfd_MockCredentials = nullptr;
WFD_WRAP_FUNC1(wfd_MockCredentials, char const *, wf_credentials_type, struct wf_credentials const *);
WFD_WRAP_FUNC2(wfd_MockCredentials, char const *, wf_credentials_get, struct wf_credentials const *, char const *);
}
namespace webfused_test
{
MockCredentials::MockCredentials()
{
wfd_MockCredentials = this;
}
MockCredentials::~MockCredentials()
{
wfd_MockCredentials = nullptr;
}
}

29
test/mock/credentials.hpp Normal file
View File

@ -0,0 +1,29 @@
#ifndef WFD_MOCK_CREDENTIALS_HPP
#define WFD_MOCK_CREDENTIALS_HPP
#include <gmock/gmock.h>
#include "webfuse/credentials.h"
namespace webfused_test
{
class ICredentials
{
public:
virtual ~ICredentials() = default;
virtual char const * wf_credentials_type(struct wf_credentials const * credentials) = 0;
virtual char const * wf_credentials_get(struct wf_credentials const * credentials, char const * key) = 0;
};
class MockCredentials: public ICredentials
{
public:
MockCredentials();
virtual ~MockCredentials();
MOCK_METHOD1(wf_credentials_type, char const*(struct wf_credentials const * credentials));
MOCK_METHOD2(wf_credentials_get, char const *(struct wf_credentials const * credentials, char const * key));
};
}
#endif

27
test/mock/libconfig.cc Normal file
View File

@ -0,0 +1,27 @@
#include "mock/libconfig.hpp"
#include "util/wrap.hpp"
extern "C"
{
static webfused_test::ILibConfig * wfd_MockLibConfig = nullptr;
WFD_WRAP_FUNC2(wfd_MockLibConfig, config_setting_t *, config_setting_get_elem,
config_setting_t const *, unsigned int);
}
namespace webfused_test
{
MockLibConfig::MockLibConfig()
{
wfd_MockLibConfig = this;
}
MockLibConfig::~MockLibConfig()
{
wfd_MockLibConfig = nullptr;
}
}

32
test/mock/libconfig.hpp Normal file
View File

@ -0,0 +1,32 @@
#ifndef WFD_MOCK_LIBCONFIG_HPP
#define WFD_MOCK_LIBCONFIG_HPP
#include <libconfig.h>
#include <gmock/gmock.h>
namespace webfused_test
{
class ILibConfig
{
public:
virtual ~ILibConfig() = default;
virtual config_setting_t * config_setting_get_elem(
config_setting_t const * setting,
unsigned int i) = 0;
};
class MockLibConfig: public ILibConfig
{
public:
MockLibConfig();
~MockLibConfig() override;
MOCK_METHOD2(config_setting_get_elem, config_setting_t * (
config_setting_t const * setting,
unsigned int i));
};
}
#endif

31
test/mock/linux.cc Normal file
View File

@ -0,0 +1,31 @@
#include "mock/linux.hpp"
#include "util/wrap.hpp"
extern "C"
{
static webfused_test::ILinux * wfd_MockLinux = nullptr;
WFD_WRAP_FUNC0( wfd_MockLinux, uid_t, getuid);
WFD_WRAP_FUNC1( wfd_MockLinux, struct group *, getgrnam, char const *);
WFD_WRAP_FUNC1( wfd_MockLinux, int, setgid, gid_t);
WFD_WRAP_FUNC2( wfd_MockLinux, int, setgroups, int, gid_t *);
WFD_WRAP_FUNC1( wfd_MockLinux, struct passwd *, getpwnam, char const *);
WFD_WRAP_FUNC1( wfd_MockLinux, int, setuid, uid_t);
}
namespace webfused_test
{
MockLinux::MockLinux()
{
wfd_MockLinux = this;
}
MockLinux::~MockLinux()
{
wfd_MockLinux = nullptr;
}
}

41
test/mock/linux.hpp Normal file
View File

@ -0,0 +1,41 @@
#ifndef WFD_MOCK_LINUX_HPP
#define WFD_MOCK_LINUX_HPP
#include <unistd.h>
#include <sys/types.h>
#include <grp.h>
#include <pwd.h>
#include <gmock/gmock.h>
namespace webfused_test
{
class ILinux
{
public:
virtual ~ILinux() = default;
virtual uid_t getuid() = 0;
virtual struct group * getgrnam(char const * name) = 0;
virtual int setgid(gid_t gid) = 0;
virtual int setgroups(int size, gid_t * list) = 0;
virtual struct passwd * getpwnam(char const * name) = 0;
virtual int setuid(uid_t uid) = 0;
};
class MockLinux: public ILinux
{
public:
MockLinux();
~MockLinux();
MOCK_METHOD0(getuid, uid_t());
MOCK_METHOD1(getgrnam, struct group * (char const * name));
MOCK_METHOD1(setgid, int (gid_t gid));
MOCK_METHOD2(setgroups, int (int size, gid_t * list));
MOCK_METHOD1(getpwnam, struct passwd * (char const * name));
MOCK_METHOD1(setuid, int (uid_t uid));
};
}
#endif

58
test/mock/logger.cc Normal file
View File

@ -0,0 +1,58 @@
#include "mock/logger.hpp"
#include "webfused/log/logger.h"
#include "webfused/log/log.h"
namespace webfused_test
{
MockLogger::MockLogger(bool omit_init)
: close_on_destruct(!omit_init)
{
if (!omit_init)
{
wfd_logger_init(
WFD_LOGLEVEL_ALL,
&wfd_MockLogger_log,
&wfd_MockLogger_onclose,
getUserData());
}
}
MockLogger::~MockLogger()
{
if (close_on_destruct)
{
wfd_logger_close();
}
}
void * MockLogger::getUserData()
{
ILogger * logger = this;
return reinterpret_cast<void*>(logger);
}
}
extern "C"
{
using webfused_test::ILogger;
void wfd_MockLogger_log(
void * user_data,
int level,
char const * format,
va_list args)
{
ILogger * logger = reinterpret_cast<ILogger*>(user_data);
logger->log(level, format, args);
}
void wfd_MockLogger_onclose(
void * user_data)
{
ILogger * logger = reinterpret_cast<ILogger*>(user_data);
logger->onclose();
}
}

47
test/mock/logger.hpp Normal file
View File

@ -0,0 +1,47 @@
#ifndef WFD_MOCK_LOGGER_HPP
#define WFD_MOCK_LOGGER_HPP
#include <gmock/gmock.h>
#include <cstdarg>
namespace webfused_test
{
class ILogger
{
public:
virtual ~ILogger() = default;
virtual void log(int level, char const * format, va_list args) = 0;
virtual void onclose() = 0;
};
class MockLogger: public ILogger
{
public:
explicit MockLogger(bool omit_init = false);
~MockLogger() override;
MOCK_METHOD3(log, void(int level, char const * format, va_list args));
MOCK_METHOD0(onclose, void(void));
void * getUserData();
private:
bool close_on_destruct;
};
}
extern "C"
{
extern void wfd_MockLogger_log(
void * user_data,
int level,
char const * format,
va_list args);
extern void wfd_MockLogger_onclose(
void * user_data);
}
#endif

29
test/mock/pam.cc Normal file
View File

@ -0,0 +1,29 @@
#include "mock/pam.hpp"
#include "util/wrap.hpp"
extern "C"
{
static webfused_test::IPam * wfd_MockPam = nullptr;
WFD_WRAP_FUNC4(wfd_MockPam, int, pam_start, char const *, char const *, struct pam_conv const *, pam_handle_t **);
WFD_WRAP_FUNC2(wfd_MockPam, int, pam_end, pam_handle_t *, int);
WFD_WRAP_FUNC2(wfd_MockPam, int, pam_authenticate, pam_handle_t *, int);
WFD_WRAP_FUNC2(wfd_MockPam, int, pam_acct_mgmt, pam_handle_t *, int);
WFD_WRAP_FUNC2(wfd_MockPam, char const *, pam_strerror, pam_handle_t *, int);
}
namespace webfused_test
{
MockPam::MockPam()
{
wfd_MockPam = this;
}
MockPam::~MockPam()
{
wfd_MockPam = nullptr;
}
}

45
test/mock/pam.hpp Normal file
View File

@ -0,0 +1,45 @@
#ifndef WFD_MOCK_PAM_HPP
#define WFD_MOCK_PAM_HPP
#include <security/pam_appl.h>
#include <gmock/gmock.h>
namespace webfused_test
{
class IPam
{
public:
virtual ~IPam() = default;
virtual int pam_start(
char const * service_name,
char const * user,
struct pam_conv const * conversation,
pam_handle_t * * handle) = 0;
virtual int pam_end(pam_handle_t * handle, int status) = 0;
virtual int pam_authenticate(pam_handle_t * handle, int flags) = 0;
virtual int pam_acct_mgmt(pam_handle_t * handle, int flags) = 0;
virtual char const * pam_strerror(pam_handle_t * handle, int errnum) = 0;
};
class MockPam: public IPam
{
public:
MockPam();
~MockPam() override;
MOCK_METHOD4(pam_start, int (
char const * service_name,
char const * user,
struct pam_conv const * conversation,
pam_handle_t * * handle));
MOCK_METHOD2(pam_end, int(pam_handle_t * handle, int status));
MOCK_METHOD2(pam_authenticate, int(pam_handle_t * handle, int flags));
MOCK_METHOD2(pam_acct_mgmt, int (pam_handle_t * handle, int flags));
MOCK_METHOD2(pam_strerror, char const * (pam_handle_t * handle, int errnum));
};
}
#endif

25
test/mock/server.cc Normal file
View File

@ -0,0 +1,25 @@
#include "mock/server.hpp"
#include "util/wrap.hpp"
extern "C"
{
static webfused_test::IServer * wfd_MockServer = nullptr;
WFD_WRAP_FUNC1(wfd_MockServer, struct wf_server *, wf_server_create, struct wf_server_config *);
}
namespace webfused_test
{
MockServer::MockServer()
{
wfd_MockServer = this;
}
MockServer::~MockServer()
{
wfd_MockServer = nullptr;
}
}

28
test/mock/server.hpp Normal file
View File

@ -0,0 +1,28 @@
#ifndef WFD_MOCK_SERVER_HPP
#define WFD_MOCK_SERVER_HPP
#include <webfuse/server.h>
#include <gmock/gmock.h>
namespace webfused_test
{
class IServer
{
public:
virtual ~IServer() = default;
virtual struct wf_server * wf_server_create(struct wf_server_config * config) = 0;
};
class MockServer: public IServer
{
public:
MockServer();
~MockServer() override;
MOCK_METHOD1(wf_server_create, struct wf_server * (struct wf_server_config * config));
};
}
#endif

27
test/mock/settings.cc Normal file
View File

@ -0,0 +1,27 @@
#include "mock/settings.hpp"
#include "util/wrap.hpp"
extern "C"
{
static webfused_test::ISettings * wfd_MockSettings = nullptr;
WFD_WRAP_FUNC2(wfd_MockSettings, char const *, wfd_settings_get_string, struct wfd_settings *, char const *);
WFD_WRAP_FUNC3(wfd_MockSettings, char const *, wfd_settings_get_string_or_default,
struct wfd_settings *, char const *, char const *);
WFD_WRAP_FUNC2(wfd_MockSettings, bool, wfd_settings_get_bool, struct wfd_settings *, char const *);
}
namespace webfused_test
{
MockSettings::MockSettings()
{
wfd_MockSettings = this;
}
MockSettings::~MockSettings()
{
wfd_MockSettings = nullptr;
}
}

33
test/mock/settings.hpp Normal file
View File

@ -0,0 +1,33 @@
#ifndef WFD_MOCK_AUTH_SETTINGS_HPP
#define WFD_MOCK_AUTH_SETTINGS_HPP
#include <gmock/gmock.h>
#include "webfused/config/settings.h"
namespace webfused_test
{
class ISettings
{
public:
virtual ~ISettings() = default;
virtual char const * wfd_settings_get_string(wfd_settings * settings, char const * key) = 0;
virtual char const * wfd_settings_get_string_or_default(wfd_settings * settings, char const * key, char const * default_value) = 0;
virtual bool wfd_settings_get_bool(wfd_settings * settings, char const * key) = 0;
};
class MockSettings: public ISettings
{
public:
MockSettings();
~MockSettings() override;
MOCK_METHOD2(wfd_settings_get_string, char const * (wfd_settings * settings, char const * key));
MOCK_METHOD3(wfd_settings_get_string_or_default, char const * (wfd_settings * settings, char const * key, char const * default_value));
MOCK_METHOD2(wfd_settings_get_bool, bool (wfd_settings * settings, char const * key));
};
}
#endif

144
test/mountpoint_factory.cc Normal file
View File

@ -0,0 +1,144 @@
#include <gtest/gtest.h>
#include "webfused/mountpoint_factory.h"
#include "webfused/util/string_list.h"
#include <webfuse/mountpoint.h>
#include <cstring>
TEST(mountpoint_factory, create)
{
wfd_mountpoint_factory * factory = wfd_mountpoint_factory_create();
ASSERT_NE(nullptr, factory);
wfd_mountpoint_factory_dispose(factory);
}
TEST(mountpiont_factory, add_filesystem)
{
wfd_mountpoint_factory * factory = wfd_mountpoint_factory_create();
ASSERT_NE(nullptr, factory);
struct wfd_string_list mount_options = {0, 0, nullptr};
bool success = wfd_mountpoint_factory_add_filesystem(factory, "test", "/tmp/webfused_test", &mount_options);
ASSERT_TRUE(success);
wfd_mountpoint_factory_dispose(factory);
}
TEST(mountpiont_factory, add_filesystem_fail_to_add_twice)
{
wfd_mountpoint_factory * factory = wfd_mountpoint_factory_create();
ASSERT_NE(nullptr, factory);
struct wfd_string_list mount_options = {0, 0, nullptr};
bool success = wfd_mountpoint_factory_add_filesystem(factory, "test", "/tmp/webfused_test", &mount_options);
ASSERT_TRUE(success);
success = wfd_mountpoint_factory_add_filesystem(factory, "test", "/tmp/webfused_test", &mount_options);
ASSERT_FALSE(success);
wfd_mountpoint_factory_dispose(factory);
}
TEST(mountpiont_factory, add_filesystem_multi)
{
wfd_mountpoint_factory * factory = wfd_mountpoint_factory_create();
ASSERT_NE(nullptr, factory);
for (size_t i = 0; i < 24; i++)
{
char name[10];
snprintf(name, 10, "test_%zu", i);
struct wfd_string_list mount_options = {0, 0, nullptr};
bool success = wfd_mountpoint_factory_add_filesystem(factory, name, "/tmp/webfused_test", &mount_options);
ASSERT_TRUE(success) << i;
}
wfd_mountpoint_factory_dispose(factory);
}
TEST(mountpiont_factory, add_filesystem_fail_invalid_path)
{
wfd_mountpoint_factory * factory = wfd_mountpoint_factory_create();
ASSERT_NE(nullptr, factory);
struct wfd_string_list mount_options = {0, 0, nullptr};
bool success = wfd_mountpoint_factory_add_filesystem(factory, "test", "/do/not/allow/nested/paths", &mount_options);
ASSERT_FALSE(success);
wfd_mountpoint_factory_dispose(factory);
}
TEST(mountpiont_factory, create_mountpoint)
{
wfd_mountpoint_factory * factory = wfd_mountpoint_factory_create();
ASSERT_NE(nullptr, factory);
struct wfd_string_list mount_options = {0, 0, nullptr};
bool success = wfd_mountpoint_factory_add_filesystem(factory, "test", "/tmp/webfuse_test", &mount_options);
ASSERT_TRUE(success);
wf_mountpoint * mountpoint = wfd_mountpoint_factory_create_mountpoint("test", factory);
ASSERT_NE(nullptr, mountpoint);
ASSERT_STREQ("/tmp/webfuse_test", wf_mountpoint_get_path(mountpoint));
wf_mountpoint_dispose(mountpoint);
wfd_mountpoint_factory_dispose(factory);
}
TEST(mountpiont_factory, create_mountpoint_fail_already_in_use)
{
wfd_mountpoint_factory * factory = wfd_mountpoint_factory_create();
ASSERT_NE(nullptr, factory);
struct wfd_string_list mount_options = {0, 0, nullptr};
bool success = wfd_mountpoint_factory_add_filesystem(factory, "test", "/tmp/webfuse_test", &mount_options);
ASSERT_TRUE(success);
wf_mountpoint * mountpoint = wfd_mountpoint_factory_create_mountpoint("test", factory);
ASSERT_NE(nullptr, mountpoint);
ASSERT_STREQ("/tmp/webfuse_test", wf_mountpoint_get_path(mountpoint));
wf_mountpoint * mountpoint2 = wfd_mountpoint_factory_create_mountpoint("test", factory);
ASSERT_EQ(nullptr, mountpoint2);
wf_mountpoint_dispose(mountpoint);
wfd_mountpoint_factory_dispose(factory);
}
TEST(mountpiont_factory, create_mountpoint_fail_unknown_filesystem)
{
wfd_mountpoint_factory * factory = wfd_mountpoint_factory_create();
ASSERT_NE(nullptr, factory);
struct wfd_string_list mount_options = {0, 0, nullptr};
bool success = wfd_mountpoint_factory_add_filesystem(factory, "test", "/tmp/webfuse_test", &mount_options);
ASSERT_TRUE(success);
wf_mountpoint * mountpoint = wfd_mountpoint_factory_create_mountpoint("unkown", factory);
ASSERT_EQ(nullptr, mountpoint);
wfd_mountpoint_factory_dispose(factory);
}
TEST(mountpiont_factory, create_mountpoint_multi)
{
wfd_mountpoint_factory * factory = wfd_mountpoint_factory_create();
ASSERT_NE(nullptr, factory);
struct wfd_string_list mount_options = {0, 0, nullptr};
bool success = wfd_mountpoint_factory_add_filesystem(factory, "test", "/tmp/webfuse_test", &mount_options);
ASSERT_TRUE(success);
for(int i = 0; i < 5; i++)
{
wf_mountpoint * mountpoint = wfd_mountpoint_factory_create_mountpoint("test", factory);
ASSERT_NE(nullptr, mountpoint) << i;
ASSERT_STREQ("/tmp/webfuse_test", wf_mountpoint_get_path(mountpoint)) << i;
wf_mountpoint_dispose(mountpoint);
}
wfd_mountpoint_factory_dispose(factory);
}

14
test/test_passwd.json Normal file
View File

@ -0,0 +1,14 @@
{
"meta": {
"type": "wf-userdb",
"major": 1,
"minor": 0,
"hash_algorithm": "sha512"
},
"users": {
"bob": {
"password_hash": "e51e27ce47054feead3d83068d47f2a07307d4877ac67da668ef43e0e466fe8c7b66651af14fdb8d48c51592ef5afa0c63f874d20861c6b9ef8e6513bfcaa330",
"salt": "b3be6979921edecfea88c50d0d1ec40b7f8c383831b2276c65969ead18e47c03"
}
}
}

407
test/userdb.cc Normal file
View File

@ -0,0 +1,407 @@
#include "userdb/userdb.h"
#include <gtest/gtest.h>
TEST(userdb, load_file)
{
userdb * db = userdb_create("");
bool success = userdb_load_file(db, "test_passwd.json");
ASSERT_TRUE(success);
ASSERT_TRUE(userdb_check(db, "bob", "secret"));
userdb_dispose(db);
}
TEST(userdb, load_file_failed_no_file)
{
userdb * db = userdb_create("");
bool success = userdb_load_file(db, "non_existing.json");
ASSERT_FALSE(success);
userdb_dispose(db);
}
TEST(userdb, save)
{
{
userdb * db = userdb_create("");
userdb_add(db, "bob", "secret");
ASSERT_TRUE(userdb_save(db, "/tmp/webfused_test.json"));
userdb_dispose(db);
}
{
userdb * db = userdb_create("");
ASSERT_TRUE(userdb_load_file(db, "/tmp/webfused_test.json"));
ASSERT_TRUE(userdb_check(db, "bob", "secret"));
userdb_dispose(db);
}
}
TEST(userdb, add)
{
userdb * db = userdb_create("");
userdb_add(db, "bob", "secret");
ASSERT_TRUE(userdb_check(db, "bob", "secret"));
ASSERT_FALSE(userdb_check(db, "bob", "i_dont_know"));
ASSERT_FALSE(userdb_check(db, "anna", "secret"));
userdb_dispose(db);
}
TEST(userdb, remove)
{
userdb * db = userdb_create("");
ASSERT_NE(nullptr, db);
userdb_add(db, "bob", "secret");
ASSERT_TRUE(userdb_check(db, "bob", "secret"));
userdb_remove(db, "bob");
ASSERT_FALSE(userdb_check(db, "bob", "secret"));
userdb_dispose(db);
}
TEST(userdb, update)
{
userdb * db = userdb_create("");
ASSERT_NE(nullptr, db);
userdb_add(db, "bob", "secret");
ASSERT_TRUE(userdb_check(db, "bob", "secret"));
userdb_add(db, "bob", "new_secret");
ASSERT_FALSE(userdb_check(db, "bob", "secret"));
ASSERT_TRUE(userdb_check(db, "bob", "new_secret"));
userdb_dispose(db);
}
TEST(userdb, load_string)
{
userdb * db = userdb_create("");
char const contents[] =
"{"
"\"meta\": {"
" \"type\": \"wf-userdb\","
" \"major\": 1,"
" \"minor\": 0,"
" \"hash_algorithm\": \"sha512\""
"},"
"\"users\": {"
"}"
"}"
;
bool success = userdb_load_string(db, contents);
ASSERT_TRUE(success);
userdb_dispose(db);
}
TEST(userdb, load_fail_no_json)
{
userdb * db = userdb_create("");
char const contents[] = "brummni";
bool success = userdb_load_string(db, contents);
ASSERT_FALSE(success);
userdb_dispose(db);
}
TEST(userdb, load_fail_invalid_type)
{
userdb * db = userdb_create("");
char const contents[] =
"{"
"\"meta\": {"
" \"type\": \"any-userdb\","
" \"major\": 1,"
" \"minor\": 0,"
" \"hash_algorithm\": \"sha512\""
"},"
"\"users\": {"
"}"
"}"
;
bool success = userdb_load_string(db, contents);
ASSERT_FALSE(success);
userdb_dispose(db);
}
TEST(userdb, load_fail_invalid_version)
{
userdb * db = userdb_create("");
char const contents[] =
"{"
"\"meta\": {"
" \"type\": \"wf-userdb\","
" \"major\": 2,"
" \"minor\": 0,"
" \"hash_algorithm\": \"sha512\""
"},"
"\"users\": {"
"}"
"}"
;
bool success = userdb_load_string(db, contents);
ASSERT_FALSE(success);
userdb_dispose(db);
}
TEST(userdb, load_fail_missing_type)
{
userdb * db = userdb_create("");
char const contents[] =
"{"
"\"meta\": {"
" \"major\": 1,"
" \"minor\": 0,"
" \"hash_algorithm\": \"sha512\""
"},"
"\"users\": {"
"}"
"}"
;
bool success = userdb_load_string(db, contents);
ASSERT_FALSE(success);
userdb_dispose(db);
}
TEST(userdb, load_fail_type_not_string)
{
userdb * db = userdb_create("");
char const contents[] =
"{"
"\"meta\": {"
" \"type\": 42,"
" \"major\": 1,"
" \"minor\": 0,"
" \"hash_algorithm\": \"sha512\""
"},"
"\"users\": {"
"}"
"}"
;
bool success = userdb_load_string(db, contents);
ASSERT_FALSE(success);
userdb_dispose(db);
}
TEST(userdb, load_fail_missing_major_version)
{
userdb * db = userdb_create("");
char const contents[] =
"{"
"\"meta\": {"
" \"type\": \"wf-userdb\","
" \"minor\": 0,"
" \"hash_algorithm\": \"sha512\""
"},"
"\"users\": {"
"}"
"}"
;
bool success = userdb_load_string(db, contents);
ASSERT_FALSE(success);
userdb_dispose(db);
}
TEST(userdb, load_fail_major_version_not_int)
{
userdb * db = userdb_create("");
char const contents[] =
"{"
"\"meta\": {"
" \"type\": \"wf-userdb\","
" \"major\": false,"
" \"minor\": 0,"
" \"hash_algorithm\": \"sha512\""
"},"
"\"users\": {"
"}"
"}"
;
bool success = userdb_load_string(db, contents);
ASSERT_FALSE(success);
userdb_dispose(db);
}
TEST(userdb, load_fail_missing_minor_version)
{
userdb * db = userdb_create("");
char const contents[] =
"{"
"\"meta\": {"
" \"type\": \"wf-userdb\","
" \"major\": 1,"
" \"hash_algorithm\": \"sha512\""
"},"
"\"users\": {"
"}"
"}"
;
bool success = userdb_load_string(db, contents);
ASSERT_FALSE(success);
userdb_dispose(db);
}
TEST(userdb, load_fail_minor_version_not_int)
{
userdb * db = userdb_create("");
char const contents[] =
"{"
"\"meta\": {"
" \"type\": \"wf-userdb\","
" \"major\": 1,"
" \"minor\": false,"
" \"hash_algorithm\": \"sha512\""
"},"
"\"users\": {"
"}"
"}"
;
bool success = userdb_load_string(db, contents);
ASSERT_FALSE(success);
userdb_dispose(db);
}
TEST(userdb, load_fail_missing_hash_alg)
{
userdb * db = userdb_create("");
char const contents[] =
"{"
"\"meta\": {"
" \"type\": \"wf-userdb\","
" \"major\": 1,"
" \"minor\": 0,"
"},"
"\"users\": {"
"}"
"}"
;
bool success = userdb_load_string(db, contents);
ASSERT_FALSE(success);
userdb_dispose(db);
}
TEST(userdb, load_fail_hash_alg_not_string)
{
userdb * db = userdb_create("");
char const contents[] =
"{"
"\"meta\": {"
" \"type\": \"wf-userdb\","
" \"major\": 1,"
" \"minor\": 0,"
" \"hash_algorithm\": 42"
"},"
"\"users\": {"
"}"
"}"
;
bool success = userdb_load_string(db, contents);
ASSERT_FALSE(success);
userdb_dispose(db);
}
TEST(userdb, load_fail_missing_meta)
{
userdb * db = userdb_create("");
char const contents[] =
"{"
"\"users\": {"
"}"
"}"
;
bool success = userdb_load_string(db, contents);
ASSERT_FALSE(success);
userdb_dispose(db);
}
TEST(userdb, load_fail_unsupported_hash)
{
userdb * db = userdb_create("");
char const contents[] =
"{"
"\"meta\": {"
" \"type\": \"wf-userdb\","
" \"major\": 1,"
" \"minor\": 0,"
" \"hash_algorithm\": \"brummni\""
"},"
"\"users\": {"
"}"
"}"
;
bool success = userdb_load_string(db, contents);
ASSERT_FALSE(success);
userdb_dispose(db);
}
TEST(userdb, fail_missing_user_salt)
{
userdb * db = userdb_create("");
char const contents[] =
"{"
"\"meta\": {"
" \"type\": \"wf-userdb\","
" \"major\": 1,"
" \"minor\": 0,"
" \"hash_algorithm\": \"sha512\""
"},"
"\"users\": {"
" \"bob\": {"
" \"password_hash\": \"e51e27ce47054feead3d83068d47f2a07307d4877ac67da668ef43e0e466fe8c7b66651af14fdb8d48c51592ef5afa0c63f874d20861c6b9ef8e6513bfcaa330\""
" }"
"}"
"}"
;
bool success = userdb_load_string(db, contents);
ASSERT_TRUE(success);
ASSERT_FALSE(userdb_check(db, "bob", "secret"));
userdb_dispose(db);
}
TEST(userdb, fail_missing_user_hash)
{
userdb * db = userdb_create("");
char const contents[] =
"{"
"\"meta\": {"
" \"type\": \"wf-userdb\","
" \"major\": 1,"
" \"minor\": 0,"
" \"hash_algorithm\": \"sha512\""
"},"
"\"users\": {"
" \"bob\": {"
" \"salt\": \"b3be6979921edecfea88c50d0d1ec40b7f8c383831b2276c65969ead18e47c03\""
" }"
"}"
"}"
;
bool success = userdb_load_string(db, contents);
ASSERT_TRUE(success);
ASSERT_FALSE(userdb_check(db, "bob", "secret"));
userdb_dispose(db);
}

44
test/util/string_list.cc Normal file
View File

@ -0,0 +1,44 @@
#include "webfused/util/string_list.h"
#include <gtest/gtest.h>
TEST(string_list, init_cleanup)
{
wfd_string_list list;
wfd_string_list_init(&list);
ASSERT_EQ(0, list.size);
wfd_string_list_cleanup(&list);
}
TEST(string_list, add)
{
wfd_string_list list;
wfd_string_list_init(&list);
wfd_string_list_add(&list, "value");
ASSERT_EQ(1, list.size);
ASSERT_STREQ("value", list.items[0]);
wfd_string_list_cleanup(&list);
}
TEST(string_list, add_many)
{
wfd_string_list list;
wfd_string_list_init(&list);
constexpr size_t count = 256;
for (size_t i = 0; i < count; i++)
{
wfd_string_list_add(&list, "value");
}
ASSERT_EQ(count, list.size);
for (size_t i = 0; i < count; i++)
{
ASSERT_STREQ("value", list.items[i]);
}
wfd_string_list_cleanup(&list);
}

74
test/util/wrap.hpp Normal file
View File

@ -0,0 +1,74 @@
#ifndef WFD_UTIL_WRAP_HPP
#define WFD_UTIL_WRAP_HPP
#define WFD_WRAP_FUNC0( GLOBAL_VAR, RETURN_TYPE, FUNC_NAME ) \
extern RETURN_TYPE __real_ ## FUNC_NAME (); \
RETURN_TYPE __wrap_ ## FUNC_NAME () \
{ \
if (nullptr == GLOBAL_VAR ) \
{ \
return __real_ ## FUNC_NAME (); \
} \
else \
{ \
return GLOBAL_VAR -> FUNC_NAME(); \
} \
}
#define WFD_WRAP_FUNC1( GLOBAL_VAR, RETURN_TYPE, FUNC_NAME, ARG1_TYPE ) \
extern RETURN_TYPE __real_ ## FUNC_NAME (ARG1_TYPE); \
RETURN_TYPE __wrap_ ## FUNC_NAME (ARG1_TYPE arg1) \
{ \
if (nullptr == GLOBAL_VAR ) \
{ \
return __real_ ## FUNC_NAME (arg1); \
} \
else \
{ \
return GLOBAL_VAR -> FUNC_NAME(arg1); \
} \
}
#define WFD_WRAP_FUNC2( GLOBAL_VAR, RETURN_TYPE, FUNC_NAME, ARG1_TYPE, ARG2_TYPE ) \
extern RETURN_TYPE __real_ ## FUNC_NAME (ARG1_TYPE, ARG2_TYPE); \
RETURN_TYPE __wrap_ ## FUNC_NAME (ARG1_TYPE arg1, ARG2_TYPE arg2) \
{ \
if (nullptr == GLOBAL_VAR ) \
{ \
return __real_ ## FUNC_NAME (arg1, arg2); \
} \
else \
{ \
return GLOBAL_VAR -> FUNC_NAME(arg1, arg2); \
} \
}
#define WFD_WRAP_FUNC3( GLOBAL_VAR, RETURN_TYPE, FUNC_NAME, ARG1_TYPE, ARG2_TYPE, ARG3_TYPE ) \
extern RETURN_TYPE __real_ ## FUNC_NAME (ARG1_TYPE, ARG2_TYPE, ARG3_TYPE); \
RETURN_TYPE __wrap_ ## FUNC_NAME (ARG1_TYPE arg1, ARG2_TYPE arg2, ARG3_TYPE arg3) \
{ \
if (nullptr == GLOBAL_VAR ) \
{ \
return __real_ ## FUNC_NAME (arg1, arg2, arg3); \
} \
else \
{ \
return GLOBAL_VAR -> FUNC_NAME(arg1, arg2, arg3); \
} \
}
#define WFD_WRAP_FUNC4( GLOBAL_VAR, RETURN_TYPE, FUNC_NAME, ARG1_TYPE, ARG2_TYPE, ARG3_TYPE, ARG4_TYPE ) \
extern RETURN_TYPE __real_ ## FUNC_NAME (ARG1_TYPE, ARG2_TYPE, ARG3_TYPE, ARG4_TYPE); \
RETURN_TYPE __wrap_ ## FUNC_NAME (ARG1_TYPE arg1, ARG2_TYPE arg2, ARG3_TYPE arg3, ARG4_TYPE arg4) \
{ \
if (nullptr == GLOBAL_VAR ) \
{ \
return __real_ ## FUNC_NAME (arg1, arg2, arg3, arg4); \
} \
else \
{ \
return GLOBAL_VAR -> FUNC_NAME(arg1, arg2, arg3, arg4); \
} \
}
#endif