diff --git a/.travis.yml b/.travis.yml index 19156a46..ebaa7985 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,7 +16,7 @@ matrix: - gcc before_install: - eval "${MATRIX_EVAL}" -- sudo apt-get install build-essential cmake libboost-all-dev libconfig++-dev libavcodec-dev libavutil-dev libavformat-dev ffmpeg libgraphicsmagick++1-dev libpstreams-dev libconfig++-dev libpstreams-dev libtag1-dev +- sudo apt-get install build-essential cmake libboost-all-dev libconfig++-dev libavcodec-dev libavutil-dev libavformat-dev ffmpeg libgraphicsmagick++1-dev libpstreams-dev libconfig++-dev libpstreams-dev libtag1-dev libpam0g-dev - git clone https://github.com/emweb/wt.git wt - pushd wt; - git checkout 4.2.1 diff --git a/CMakeLists.txt b/CMakeLists.txt index 2d0c04fe..8d84e7d3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,9 +19,9 @@ pkg_check_modules(GRAPHICSMAGICKXX REQUIRED GraphicsMagick++) add_subdirectory(src) -# TODO pam configuration file install(DIRECTORY approot DESTINATION share/lms) install(DIRECTORY docroot DESTINATION share/lms) -install(FILES systemd/default.service DESTINATION share/lms) +install(FILES conf/systemd/default.service DESTINATION share/lms) +install(FILES conf/pam/lms DESTINATION share/lms) install(FILES conf/lms.conf DESTINATION share/lms) diff --git a/conf/lms b/conf/lms deleted file mode 100644 index c53af2a1..00000000 --- a/conf/lms +++ /dev/null @@ -1,9 +0,0 @@ -account required pam_unix.so try_first_pass -account sufficient pam_localuser.so - -auth required pam_unix.so try_first_pass - -password required pam_deny.so - -session required pam_unix.so try_first_pass - diff --git a/conf/pam/lms b/conf/pam/lms new file mode 100644 index 00000000..fa7ad812 --- /dev/null +++ b/conf/pam/lms @@ -0,0 +1,3 @@ +account required pam_unix.so +auth required pam_unix.so +password required pam_deny.so diff --git a/systemd/default.service b/conf/systemd/default.service similarity index 100% rename from systemd/default.service rename to conf/systemd/default.service diff --git a/docroot/css/lms.css b/docroot/css/lms.css index 6f1ca489..3fecc982 100644 --- a/docroot/css/lms.css +++ b/docroot/css/lms.css @@ -483,7 +483,4 @@ a.Lms-releasename:hover, a.Lms-releasename:focus { margin-bottom: 8px; } -.hack { - margin-left: 20px; -} diff --git a/src/libs/auth/CMakeLists.txt b/src/libs/auth/CMakeLists.txt index 4f3469f6..0bcd31c1 100644 --- a/src/libs/auth/CMakeLists.txt +++ b/src/libs/auth/CMakeLists.txt @@ -20,14 +20,15 @@ target_link_libraries(lmsauth PRIVATE target_link_libraries(lmsauth PUBLIC pthread - boost_system + Boost::system wt - ${PAM_LIBRARIES} ) if (PAM_FOUND) target_compile_options(lmsauth PRIVATE "-DLMS_SUPPORT_PAM") target_sources(lmsauth PRIVATE impl/pam/PAM.cpp) + target_include_directories(lmsauth PRIVATE ${PAM_INCLUDE_DIR}) + target_link_libraries(lmsauth PRIVATE ${PAM_LIBRARIES}) endif(PAM_FOUND) install(TARGETS lmsauth DESTINATION lib) diff --git a/src/libs/auth/impl/pam/PAM.cpp b/src/libs/auth/impl/pam/PAM.cpp index 03cf0e26..93869d3f 100644 --- a/src/libs/auth/impl/pam/PAM.cpp +++ b/src/libs/auth/impl/pam/PAM.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 Emeric Poupon + * Copyright (C) 2020 Emeric Poupon * * This file is part of LMS. * @@ -29,75 +29,6 @@ namespace Auth::PAM { -static - void -freeResp(int num_msg, pam_response *response) -{ - if (response == nullptr) - return; - - for (int i = 0; i < num_msg; i++) - { - if (response[i].resp) - { - memset(response[i].resp, 0, strlen(response[i].resp)); - free(response[i].resp); - response[i].resp = nullptr; - } - } - - free(response); -} - -struct PAMConvData -{ - std::string loginName; - std::string password; -}; - -static -int -lms_conv(int msgCount, const pam_message** msgs, pam_response** resps, void* userData) -{ - if (msgCount < 1) - return PAM_CONV_ERR; - if (!resps || !msgs || !userData) - return PAM_CONV_ERR; - - const PAMConvData& convData {*static_cast(userData)}; - - pam_response* response {static_cast(malloc(sizeof(pam_response) * msgCount))}; - if (!response) - return PAM_CONV_ERR; - - for (int i {}; i < msgCount; ++i) - { - response[i].resp_retcode = 0; - response[i].resp = nullptr; - - switch (msgs[i]->msg_style) - { - case PAM_PROMPT_ECHO_ON: - // on memory allocation failure, auth fails - response[i].resp = strdup(convData.loginName.c_str()); - break; - - case PAM_PROMPT_ECHO_OFF: - response[i].resp = strdup(convData.password.c_str()); - break; - - case PAM_ERROR_MSG: - case PAM_TEXT_INFO: - default: - freeResp(i, response); - return PAM_CONV_ERR; - } - } - - *resps = response; - return PAM_SUCCESS; -} - class PAMError { public: @@ -116,9 +47,8 @@ class PAMContext { public: PAMContext(std::string_view loginName) - : _convData {std::string {loginName}, {}} { - int err {pam_start("lms", _convData.loginName.c_str(), &_conv, &_pamh)}; + int err {pam_start("lms", std::string {loginName}.c_str(), &_conv, &_pamh)}; if (err != PAM_SUCCESS) throw PAMError {"start failed", _pamh, err}; } @@ -130,13 +60,13 @@ class PAMContext LMS_LOG(AUTH, ERROR) << "end failed: " << pam_strerror(_pamh, err); } - void authenticate(const std::string& password) + void authenticate(std::string_view password) { - _convData.password = password; - int err {pam_authenticate(_pamh, 0)}; - _convData.password.clear(); + AuthenticateConvContext authContext {password}; + ScopedConvContextSetter scopedContext {*this, authContext}; - if(err != PAM_SUCCESS) + int err {pam_authenticate(_pamh, 0)}; + if (err != PAM_SUCCESS) throw PAMError {"authenticate failed", _pamh, err}; } @@ -144,12 +74,87 @@ class PAMContext { int err {pam_acct_mgmt(_pamh, PAM_SILENT)}; if (err != PAM_SUCCESS) - throw PAMError {"acct_mgmt failed", _pamh, err}; + throw PAMError {"acct_mgmt failed", _pamh, err}; } private: - PAMConvData _convData; - pam_conv _conv {lms_conv, &_convData}; + + class ConvContext + { + public: + virtual ~ConvContext() = default; + }; + + class AuthenticateConvContext final : public ConvContext + { + public: + AuthenticateConvContext(std::string_view password) : _password {password} {} + + std::string_view getPassword() const { return _password; } + + private: + std::string_view _password; + }; + + class ScopedConvContextSetter + { + public: + ScopedConvContextSetter(PAMContext& pamContext, ConvContext& convContext) + : _pamContext {pamContext} + { + _pamContext._convContext = &convContext; + } + + ~ScopedConvContextSetter() + { + _pamContext._convContext = nullptr; + } + + ScopedConvContextSetter(const ScopedConvContextSetter&) = delete; + ScopedConvContextSetter(ScopedConvContextSetter&&) = delete; + ScopedConvContextSetter& operator=(const ScopedConvContextSetter&) = delete; + ScopedConvContextSetter& operator=(ScopedConvContextSetter&&) = delete; + + private: + PAMContext& _pamContext; + }; + + + static int conv(int msgCount, const pam_message** msgs, pam_response** resps, void* userData) + { + if (msgCount < 1) + return PAM_CONV_ERR; + if (!resps || !msgs || !userData) + return PAM_CONV_ERR; + + PAMContext& context {*static_cast(userData)}; + + AuthenticateConvContext* authenticateContext = dynamic_cast(context._convContext); + if (!authenticateContext) + { + LMS_LOG(AUTH, ERROR) << "Unexpected conv!"; + return PAM_CONV_ERR; + } + + // Only expect a PAM_PROMPT_ECHO_OFF msg + if (msgCount != 1 || msgs[0]->msg_style != PAM_PROMPT_ECHO_OFF) + { + LMS_LOG(AUTH, ERROR) << "Unexpected conv message. Count = " << msgCount; + return PAM_CONV_ERR; + } + + pam_response* response {static_cast(malloc(sizeof(pam_response)))}; + if (!response) + return PAM_CONV_ERR; + + response->resp = strdup(std::string {authenticateContext->getPassword()}.c_str()); + + *resps = response; + return PAM_SUCCESS; + } + + ConvContext* _convContext {}; + pam_conv _conv {&PAMContext::conv, this}; pam_handle_t *_pamh {}; }; diff --git a/src/libs/av/CMakeLists.txt b/src/libs/av/CMakeLists.txt index b519c980..30e72176 100644 --- a/src/libs/av/CMakeLists.txt +++ b/src/libs/av/CMakeLists.txt @@ -6,24 +6,18 @@ add_library(lmsav SHARED impl/AvTypes.cpp ) +# TODO make av libs private target_include_directories(lmsav INTERFACE include + ${AVCODEC_INCLUDE_DIR} ${AVFORMAT_INCLUDE_DIR} ${AVUTIL_INCLUDE_DIR} ) -# ${AVCODEC_INCLUDE_DIR} -# ${AVDEVICE_INCLUDE_DIR} target_include_directories(lmsav PRIVATE include/ - - ${AVFORMAT_INCLUDE_DIR} - ${AVUTIL_INCLUDE_DIR} ) -# ${AVCODEC_INCLUDE_DIR} -# ${AVDEVICE_INCLUDE_DIR} -# TODO make these private target_link_libraries(lmsav PUBLIC lmsutils avformat diff --git a/src/libs/database/impl/Session.cpp b/src/libs/database/impl/Session.cpp index 17b243b6..48d3de2e 100644 --- a/src/libs/database/impl/Session.cpp +++ b/src/libs/database/impl/Session.cpp @@ -1,5 +1,5 @@ /* -auth_mode(C) 2013 Emeric Poupon + * Copyright (C) 2020 Emeric Poupon * * This file is part of LMS. * diff --git a/src/libs/utils/CMakeLists.txt b/src/libs/utils/CMakeLists.txt index 2dbf4d2c..89505632 100644 --- a/src/libs/utils/CMakeLists.txt +++ b/src/libs/utils/CMakeLists.txt @@ -25,7 +25,7 @@ target_link_libraries(lmsutils PRIVATE ) target_link_libraries(lmsutils PUBLIC - boost_system + Boost::system std::filesystem wt )