Makefile.am        |    2 -
 debian/control     |    2 -
 loolwsd.spec.in    |    4 ++
 loolwsd.xml.in     |    5 +-
 wsd/FileServer.cpp |   89 +++++++++++++++++++++++++++++++++++++++++++++++------
 wsd/LOOLWSD.cpp    |    3 +
 6 files changed, 90 insertions(+), 15 deletions(-)

New commits:
commit a2e25cc7d31f3daa011df7f7b4e40fc540d91d2a
Author: Andras Timar <andras.ti...@collabora.com>
Date:   Mon Jan 22 11:57:39 2018 +0100

    Add PAM support
    
    Possibilities are endless. With a simple /etc/pam.d/loolwsd config below,
    the user which runs loolwsd ('lool' in production environment) can login
    to admin console with normal linux password.
    
        auth       required     pam_unix.so
        account    required     pam_unix.so
    
    Change-Id: I354a7e9b4705e8fe346d17d6b6041d1406198b37
    Reviewed-on: https://gerrit.libreoffice.org/48307
    Reviewed-by: Andras Timar <andras.ti...@collabora.com>
    Tested-by: Andras Timar <andras.ti...@collabora.com>

diff --git a/Makefile.am b/Makefile.am
index 3d751207..d0e2ae2d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -36,7 +36,7 @@ if !ENABLE_DEBUG
 AM_CPPFLAGS += -DNDEBUG
 endif
 
-AM_LDFLAGS = -pthread -Wl,-E,-rpath,/snap/loolwsd/current/usr/lib $(ZLIB_LIBS)
+AM_LDFLAGS = -pthread -Wl,-E,-rpath,/snap/loolwsd/current/usr/lib -lpam 
$(ZLIB_LIBS)
 
 if ENABLE_SSL
 AM_LDFLAGS += -lssl -lcrypto
diff --git a/debian/control b/debian/control
index b89cb7ca..30bdfe04 100644
--- a/debian/control
+++ b/debian/control
@@ -1,7 +1,7 @@
 Source: loolwsd
 Section: web
 Priority: optional
-Maintainer: Tor Lillqvist <t...@collabora.com>
+Maintainer: Andras Timar <andras.ti...@collabora.com>
 Build-Depends: debhelper (>= 9), dh-systemd (>= 1.3), libcap-dev, libcap2-bin, 
libpcre3-dev, libpng-dev, libpoco-dev (>= 1.7.5), linux-libc-dev
 Standards-Version: 3.9.7
 
diff --git a/loolwsd.spec.in b/loolwsd.spec.in
index f7355b17..0933b1a3 100644
--- a/loolwsd.spec.in
+++ b/loolwsd.spec.in
@@ -88,6 +88,9 @@ install -D -m 644 sysconfig.loolwsd 
%{buildroot}/var/adm/fillup-templates
 mkdir -p %{buildroot}/etc/cron.d
 echo "#Remove old tiles once every 10 days at midnight" > 
%{buildroot}/etc/cron.d/loolwsd.cron
 echo "0 0 */1 * * root find /var/cache/loolwsd -name \"*.png\" -a -atime +10 
-exec rm {} \;" >> %{buildroot}/etc/cron.d/loolwsd.cron
+mkdir -p %{buildroot}/etc/pam.d
+echo "auth       required     pam_unix.so" > %{buildroot}/etc/pam.d/loolwsd
+echo "account    required     pam_unix.so" >>  %{buildroot}/etc/pam.d/loolwsd
 
 %files
 /usr/bin/loolwsd
@@ -116,6 +119,7 @@ echo "0 0 */1 * * root find /var/cache/loolwsd -name 
\"*.png\" -a -atime +10 -ex
 %endif
 
 %config(noreplace) /etc/cron.d/loolwsd.cron
+%config(noreplace) /etc/pam.d/loolwsd
 %config(noreplace) %attr(640, lool, root) /etc/loolwsd/loolwsd.xml
 %config /etc/loolwsd/loolkitconfig.xcu
 
diff --git a/loolwsd.xml.in b/loolwsd.xml.in
index 1609c7bc..31ab1a07 100644
--- a/loolwsd.xml.in
+++ b/loolwsd.xml.in
@@ -100,8 +100,9 @@
     <tile_cache_persistent desc="Should the tiles persist between two editing 
sessions of the given document?" type="bool" 
default="true">true</tile_cache_persistent>
 
     <admin_console desc="Web admin console settings.">
-        <username desc="The username of the admin console. Must be 
set."></username>
-        <password desc="The password of the admin console. Must be 
set."></password>
+        <enable_pam desc="Enable admin user authentication with PAM" 
type="bool" default="true">true</enable_pam>
+        <username desc="The username of the admin console. Must be set, if PAM 
is not enabled, otherwise it's optional."></username>
+        <password desc="The password of the admin console. Deprecated on most 
platforms. Instead, use loolconfig to set up a secure password."></password>
     </admin_console>
 
 </config>
diff --git a/wsd/FileServer.cpp b/wsd/FileServer.cpp
index 9f788818..ad4b890d 100644
--- a/wsd/FileServer.cpp
+++ b/wsd/FileServer.cpp
@@ -17,6 +17,7 @@
 #include <sys/stat.h>
 #include <unistd.h>
 #include <zlib.h>
+#include <security/pam_appl.h>
 
 #include <openssl/evp.h>
 
@@ -53,6 +54,62 @@ using Poco::Util::Application;
 
 std::map<std::string, std::pair<std::string, std::string>> 
FileServerRequestHandler::FileHash;
 
+namespace {
+
+int functionConversation(int /*num_msg*/, const struct pam_message** /*msg*/,
+                         struct pam_response **reply, void *appdata_ptr)
+{
+    *reply = (struct pam_response *)malloc(sizeof(struct pam_response));
+    (*reply)[0].resp = strdup(static_cast<char *>(appdata_ptr));
+    (*reply)[0].resp_retcode = 0;
+
+    return PAM_SUCCESS;
+}
+
+bool isPamAuthOk(const std::string user, const std::string pass)
+{
+    struct pam_conv localConversation { functionConversation, nullptr };
+    pam_handle_t *localAuthHandle = NULL;
+    int retval;
+
+    localConversation.appdata_ptr = const_cast<char *>(pass.c_str());
+
+    retval = pam_start("loolwsd", user.c_str(), &localConversation, 
&localAuthHandle);
+
+    if (retval != PAM_SUCCESS)
+    {
+        LOG_ERR("pam_start returned " << retval);
+        return false;
+    }
+
+    retval = pam_authenticate(localAuthHandle, 0);
+
+    if (retval != PAM_SUCCESS)
+    {
+       if (retval == PAM_AUTH_ERR)
+       {
+           LOG_ERR("PAM authentication failure for user \"" << user << "\".");
+       }
+       else
+       {
+           LOG_ERR("pam_authenticate returned " << retval);
+       }
+       return false;
+    }
+
+    LOG_INF("PAM authentication success for user \"" << user << "\".");
+
+    retval = pam_end(localAuthHandle, retval);
+
+    if (retval != PAM_SUCCESS)
+    {
+        LOG_WRN("pam_end returned " << retval);
+    }
+
+    return true;
+}
+}
+
 bool FileServerRequestHandler::isAdminLoggedIn(const HTTPRequest& request,
                                                HTTPResponse &response)
 {
@@ -81,10 +138,12 @@ bool FileServerRequestHandler::isAdminLoggedIn(const 
HTTPRequest& request,
 
     HTTPBasicCredentials credentials(request);
     std::string userProvidedPwd = credentials.getPassword();
+    std::string userProvidedUsr = credentials.getUsername();
 
     // If no cookie found, or is invalid, let admin re-login
     const std::string user = config.getString("admin_console.username", "");
     std::string pass = config.getString("admin_console.password", "");
+    const bool pam = config.getBool("admin_console.enable_pam", "true");
 
     if (config.has("admin_console.secure_password"))
     {
@@ -99,9 +158,7 @@ bool FileServerRequestHandler::isAdminLoggedIn(const 
HTTPRequest& request,
             !Util::dataFromHexString(tokens[3], saltData))
         {
             LOG_ERR("Incorrect format detected for secure_password in config 
file."
-                    << "Denying access until correctly set."
                     << "Use loolconfig to configure admin password.");
-            return false;
         }
 
         unsigned char userProvidedPwdHash[tokens[4].size() / 2];
@@ -120,18 +177,29 @@ bool FileServerRequestHandler::isAdminLoggedIn(const 
HTTPRequest& request,
 #else
         LOG_ERR("The config file has admin_console.secure_password setting, "
                 << "but this application was compiled with old OpenSSL 
version, "
-                << "and this setting cannot be used. Falling back to plain 
text password, if it is set.");
+                << "and this setting cannot be used. Falling back to plain 
text password or to PAM, if it is set.");
 #endif
     }
 
-    if (user.empty() || pass.empty())
+    if (!pam && (user.empty() || pass.empty()))
     {
         LOG_ERR("Admin Console credentials missing. Denying access until 
set.");
         return false;
     }
 
-    if (credentials.getUsername() == user &&
-        userProvidedPwd == pass)
+    bool authenticated = false;
+
+    if (userProvidedUsr == user && userProvidedPwd == pass)
+    {
+        authenticated = true;
+    }
+
+    if (!authenticated && pam)
+    {
+        authenticated = isPamAuthOk(userProvidedUsr, userProvidedPwd);
+    }
+
+    if (authenticated)
     {
         // generate and set the cookie
         JWTAuth authAgent(sslKeyPath, "admin", "admin", "admin");
@@ -143,12 +211,13 @@ bool FileServerRequestHandler::isAdminLoggedIn(const 
HTTPRequest& request,
         cookie.setSecure(LOOLWSD::isSSLEnabled() ||
                          LOOLWSD::isSSLTermination());
         response.addCookie(cookie);
-
-        return true;
+    }
+    else
+    {
+        LOG_INF("Wrong admin credentials.");
     }
 
-    LOG_INF("Wrong admin credentials.");
-    return false;
+    return authenticated;
 }
 
 void FileServerRequestHandler::handleRequest(const HTTPRequest& request, 
Poco::MemoryInputStream& message,
diff --git a/wsd/LOOLWSD.cpp b/wsd/LOOLWSD.cpp
index 94b4c0d3..88b6f805 100644
--- a/wsd/LOOLWSD.cpp
+++ b/wsd/LOOLWSD.cpp
@@ -687,7 +687,8 @@ void LOOLWSD::initialize(Application& self)
             { "logging.file.property[3]", "false" },
             { "trace[@enable]", "false" },
             { "trace.path[@compress]", "true" },
-            { "trace.path[@snapshot]", "false" } };
+            { "trace.path[@snapshot]", "false" },
+            { "admin_console.enable_pam", "true"} };
 
     // Set default values, in case they are missing from the config file.
     AutoPtr<AppConfigMap> defConfig(new AppConfigMap(DefAppConfig));
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to