Implement libnss_securitymanager 64/76064/13
authorAleksander Zdyb <a.zdyb@samsung.com>
Wed, 22 Jun 2016 12:31:44 +0000 (14:31 +0200)
committerBartlomiej Grzelewski <b.grzelewski@samsung.com>
Mon, 22 Aug 2016 13:59:56 +0000 (15:59 +0200)
It's a Name Service Switch plugin needed to apply
additional, resource related groups for users.

Change-Id: Ie702a22e73e9a23ef71d595bce44ec17bf8b7dde

packaging/libnss-security-manager.manifest [new file with mode: 0644]
packaging/security-manager.spec
src/CMakeLists.txt
src/nss/CMakeLists.txt [new file with mode: 0644]
src/nss/nss_securitymanager.cpp [new file with mode: 0644]
systemd/security-manager.service.in

diff --git a/packaging/libnss-security-manager.manifest b/packaging/libnss-security-manager.manifest
new file mode 100644 (file)
index 0000000..a76fdba
--- /dev/null
@@ -0,0 +1,5 @@
+<manifest>
+       <request>
+               <domain name="_" />
+       </request>
+</manifest>
index 1a76783..6251681 100644 (file)
@@ -7,6 +7,7 @@ License:    Apache-2.0
 Source0:    %{name}-%{version}.tar.gz
 Source1:    security-manager.manifest
 Source3:    libsecurity-manager-client.manifest
+Source4:    libnss-security-manager.manifest
 Requires: security-manager-policy
 Requires: nether
 Requires(post): sqlite3
@@ -51,6 +52,15 @@ Requires:   libsecurity-manager-client = %{version}-%{release}
 %description -n libsecurity-manager-client-devel
 Development files needed for using the security manager client
 
+%package -n libnss-security-manager
+Summary:    Security Manager NSS library
+Group:      Security/Libraries
+Requires(post): /sbin/ldconfig
+Requires(postun): /sbin/ldconfig
+
+%description -n libnss-security-manager
+Tizen Security Manager NSS library
+
 %package policy
 Summary:    Security manager policy
 Group:      Security/Access Control
@@ -67,6 +77,7 @@ Set of security rules that constitute security policy in the system
 %setup -q
 cp %{SOURCE1} .
 cp %{SOURCE3} .
+cp %{SOURCE4} .
 
 %build
 %if 0%{?sec_build_binary_debug_enable}
@@ -92,14 +103,17 @@ rm -rf %{buildroot}
 mkdir -p %{buildroot}%{_datadir}/license
 cp LICENSE %{buildroot}%{_datadir}/license/%{name}
 cp LICENSE %{buildroot}%{_datadir}/license/libsecurity-manager-client
+cp LICENSE %{buildroot}%{_datadir}/license/libnss-security-manager
 %make_install
 
 mkdir -p %{buildroot}/%{_unitdir}/sockets.target.wants
 mkdir -p %{buildroot}/%{_unitdir}/sysinit.target.wants
 mkdir -p %{buildroot}/%{_unitdir}/basic.target.wants
+mkdir -p %{buildroot}/%{_unitdir}/dbus.service.wants
 ln -s ../security-manager.socket %{buildroot}/%{_unitdir}/sockets.target.wants/security-manager.socket
 ln -s ../security-manager-cleanup.service %{buildroot}/%{_unitdir}/sysinit.target.wants/security-manager-cleanup.service
 ln -s ../security-manager-rules-loader.service %{buildroot}/%{_unitdir}/basic.target.wants/security-manager-rules-loader.service
+ln -s ../security-manager.service %{buildroot}/%{_unitdir}/dbus.service.wants/security-manager.service
 
 mkdir -p %{buildroot}/%{TZ_SYS_DB}
 touch %{buildroot}/%{TZ_SYS_DB}/.security-manager.db
@@ -148,6 +162,10 @@ fi
 
 %postun -n libsecurity-manager-client -p /sbin/ldconfig
 
+%post -n libnss-security-manager -p /sbin/ldconfig
+
+%postun -n libnss-security-manager -p /sbin/ldconfig
+
 %post policy
 %{_bindir}/security-manager-policy-reload
 
@@ -194,6 +212,13 @@ fi
 %{_includedir}/security-manager/*.h
 %{_libdir}/pkgconfig/security-manager.pc
 
+%files -n libnss-security-manager
+%manifest libnss-security-manager.manifest
+%defattr(-,root,root,-)
+%%attr(-,root,root) %{_unitdir}/dbus.service.wants/security-manager.service
+%{_libdir}/libnss_securitymanager.so.*
+%{_datadir}/license/libnss-security-manager
+
 %files -n security-manager-policy
 %manifest %{name}.manifest
 %{_datadir}/security-manager/policy
index 50d6dd1..f0fa9e0 100644 (file)
@@ -4,15 +4,18 @@ SET(CLIENT_PATH  ${PROJECT_SOURCE_DIR}/src/client)
 SET(SERVER_PATH  ${PROJECT_SOURCE_DIR}/src/server)
 SET(DPL_PATH     ${PROJECT_SOURCE_DIR}/src/dpl)
 SET(CMD_PATH     ${PROJECT_SOURCE_DIR}/src/cmd)
+SET(NSS_PATH     ${PROJECT_SOURCE_DIR}/src/nss)
 
 SET(TARGET_SERVER "security-manager")
 SET(TARGET_CLIENT "security-manager-client")
 SET(TARGET_COMMON "security-manager-commons")
 SET(TARGET_CMD    "security-manager-cmd")
 SET(TARGET_CLEANUP "security-manager-cleanup")
+SET(TARGET_NSS     "security-manager-nss")
 
 ADD_SUBDIRECTORY(include)
 ADD_SUBDIRECTORY(common)
 ADD_SUBDIRECTORY(client)
 ADD_SUBDIRECTORY(server)
 ADD_SUBDIRECTORY(cmd)
+ADD_SUBDIRECTORY(nss)
diff --git a/src/nss/CMakeLists.txt b/src/nss/CMakeLists.txt
new file mode 100644 (file)
index 0000000..318c38c
--- /dev/null
@@ -0,0 +1,33 @@
+SET(NSS_PLUGIN_VERSION_MAJOR 2)
+SET(NSS_PLUGIN_VERSION ${NSS_PLUGIN_VERSION_MAJOR}.0.0)
+
+SET(LIBRARY_FILE_NAME "nss_securitymanager")
+
+INCLUDE_DIRECTORIES(
+    ${INCLUDE_PATH}
+    ${CLIENT_PATH}/include
+    ${NSS_PATH}/include
+    ${DPL_PATH}/core/include
+    ${DPL_PATH}/log/include
+    )
+
+SET(NSS_SOURCES
+    ${NSS_PATH}/nss_securitymanager.cpp
+    )
+
+ADD_LIBRARY(${TARGET_NSS} SHARED ${NSS_SOURCES})
+
+SET_TARGET_PROPERTIES(${TARGET_NSS}
+    PROPERTIES
+        OUTPUT_NAME ${LIBRARY_FILE_NAME}
+        COMPILE_FLAGS "-D_GNU_SOURCE -fPIC -fvisibility=hidden"
+        SOVERSION ${NSS_PLUGIN_VERSION_MAJOR}
+        VERSION ${NSS_PLUGIN_VERSION}
+    )
+
+TARGET_LINK_LIBRARIES(${TARGET_NSS}
+    ${TARGET_CLIENT}
+    ${TARGET_COMMON}
+    )
+
+INSTALL(TARGETS ${TARGET_NSS} LIBRARY DESTINATION ${LIB_INSTALL_DIR} NAMELINK_SKIP)
diff --git a/src/nss/nss_securitymanager.cpp b/src/nss/nss_securitymanager.cpp
new file mode 100644 (file)
index 0000000..3e9009c
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ *  Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Rafal Krypa <r.krypa@samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ *
+ *  Security Manager NSS library
+ */
+/*
+ * @file        nss_securitymanager.cpp
+ * @author      Aleksander Zdyb <a.zdyb@samsung.com>
+ * @version     1.0
+ * @brief       This file contains NSS library implementation for Security Manager
+ */
+
+#include <cerrno>
+#include <cstddef>
+#include <sys/types.h>
+#include <pwd.h>
+#include <grp.h>
+#include <nss.h>
+#include <unistd.h>
+#include <cstdlib>
+
+#include <vector>
+
+#include <security-manager.h>
+
+namespace {
+
+size_t getBufferSize()
+{
+    size_t max = 4096, tmp;
+    max = max < (tmp = sysconf(_SC_GETPW_R_SIZE_MAX)) ? tmp : max;
+    return max < (tmp = sysconf(_SC_GETGR_R_SIZE_MAX)) ? tmp : max;
+}
+
+} // anonymous namespace
+
+extern "C" {
+
+
+__attribute__((visibility("default")))
+enum nss_status _nss_securitymanager_initgroups_dyn(const char *user, gid_t group_gid, long int *start,
+                                                    long int *size, gid_t **groupsp,
+                                                    long int limit, int *errnop)
+{
+    try {
+        (void) group_gid;
+
+        int ret;
+        const static size_t BUFFER_SIZE = getBufferSize();
+        const static size_t MEMORY_LIMIT = BUFFER_SIZE << 3;
+        std::vector<char> buffer(BUFFER_SIZE);
+        passwd pwnambuffer;
+        passwd *pwnam = NULL;
+
+        do {
+            ret = TEMP_FAILURE_RETRY(getpwnam_r(user, &pwnambuffer, buffer.data(), buffer.size(), &pwnam));
+            if (ret == ERANGE && buffer.size() < MEMORY_LIMIT) {
+                buffer.resize(buffer.size() << 1);
+                continue;
+            }
+        } while (0);
+
+        if (ret == ERANGE) {
+            *errnop = ENOMEM;
+            return NSS_STATUS_UNAVAIL;
+        }
+
+        if (ret || pwnam == NULL) {
+            *errnop = ENOENT;
+            return NSS_STATUS_NOTFOUND;
+        }
+
+        char **groups;
+        size_t groupsCount;
+        ret = security_manager_groups_get_for_user(pwnam->pw_uid, &groups, &groupsCount);
+
+        if (ret == SECURITY_MANAGER_ERROR_NO_SUCH_OBJECT) {
+            // If user is not managed by Security Manager, we want to apply all the groups
+            ret = security_manager_groups_get(&groups, &groupsCount);
+        }
+
+        if (ret == SECURITY_MANAGER_ERROR_MEMORY) {
+            *errnop = ENOMEM;
+            return NSS_STATUS_UNAVAIL;
+        }
+
+        if (ret == SECURITY_MANAGER_ERROR_ACCESS_DENIED) {
+            *errnop = EPERM;
+            return NSS_STATUS_UNAVAIL;
+        }
+
+        if (ret != SECURITY_MANAGER_SUCCESS) {
+            *errnop = ENOENT;
+            return NSS_STATUS_UNAVAIL;
+        }
+
+        std::vector<gid_t> result;
+
+        for (size_t i = 0; i < groupsCount; ++i) {
+            group *grnam = NULL;
+            group groupbuff;
+            do {
+                ret = TEMP_FAILURE_RETRY(getgrnam_r(groups[i], &groupbuff, buffer.data(), buffer.size(), &grnam));
+                if (ret == ERANGE && buffer.size() < MEMORY_LIMIT) {
+                    buffer.resize(buffer.size() << 1);
+                    continue;
+                }
+            } while(0);
+
+            if (ret == ERANGE) {
+                *errnop = ENOMEM;
+                return NSS_STATUS_UNAVAIL;
+            }
+
+            if (grnam)
+                result.push_back(grnam->gr_gid);
+        }
+
+        if (((*size) - (*start)) < static_cast<long int>(result.size())) {
+            long int required = (*start) + result.size();
+            // value bigger is the lowest power of 2 that is bigger than required value
+            long int bigger = 1 << ((sizeof(unsigned long) << 3) - __builtin_clzl(static_cast<unsigned long>(required)));
+
+            gid_t *ptr = static_cast<gid_t*>(realloc(*groupsp, sizeof(gid_t) * (bigger)));
+            if (!ptr) {
+                *errnop = ENOMEM;
+                return NSS_STATUS_UNAVAIL;
+            }
+            *size = bigger;
+            *groupsp = ptr;
+        }
+
+        for (auto e : result) {
+            (*groupsp)[(*start)++] = e;
+            if (limit > 0 && (*start) >= limit)
+                break;
+        }
+
+    } catch (...) {
+        // We are leaving c++ code and going to pure c so this
+        // Pokemon catch (catch them all) is realy required here.
+        return NSS_STATUS_UNAVAIL;
+    }
+    return NSS_STATUS_SUCCESS;
+}
+
+} /* extern "C" */
index 5205b36..62a7816 100644 (file)
@@ -1,5 +1,6 @@
 [Unit]
 Description=Start the security manager
+Before=dbus.service
 
 [Service]
 Type=notify
@@ -7,3 +8,6 @@ ExecStart=@BIN_INSTALL_DIR@/security-manager
 Sockets=security-manager.socket
 Restart=always
 SmackProcessLabel=System::Privileged
+
+[Install]
+WantedBy=dbus.service