add security api which uses cynara 85/278185/1
authorSooChan Lim <sc1.lim@samsung.com>
Wed, 11 May 2022 07:45:58 +0000 (16:45 +0900)
committerSooChan Lim <sc1.lim@samsung.com>
Mon, 18 Jul 2022 05:58:36 +0000 (14:58 +0900)
The keyrouter and devicemgr has to check the privilege when display
server gets the requests from these extensions. For this, security api
support the previlege check with cynara.

Change-Id: I6086e60e9d611de219b05856da6668bd7510cdc4

src/libds-tizen/meson.build
src/libds-tizen/util.h [new file with mode: 0644]
src/libds-tizen/util/meson.build [new file with mode: 0644]
src/libds-tizen/util/security.c [new file with mode: 0644]

index 4f76b68..81370e6 100644 (file)
@@ -12,6 +12,7 @@ libds_tizen_deps = [
 
 subdir('allocator')
 subdir('backend')
+subdir('util')
 
 lib_libds_tizen = shared_library('ds-tizen', libds_tizen_files,
   dependencies: libds_tizen_deps,
diff --git a/src/libds-tizen/util.h b/src/libds-tizen/util.h
new file mode 100644 (file)
index 0000000..18ad811
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef DS_UTIL_H
+#define DS_UTIL_H
+
+#include <stdint.h>
+
+#define MIN(a,b) ((a)<(b)?(a):(b))
+
+int
+tizen_security_init(void);
+
+void
+tizen_security_finish(void);
+
+bool
+tizen_security_check_privilege(pid_t pid, uid_t uid, const char *privilege);
+
+#endif
diff --git a/src/libds-tizen/util/meson.build b/src/libds-tizen/util/meson.build
new file mode 100644 (file)
index 0000000..3d34ab8
--- /dev/null
@@ -0,0 +1 @@
+libds_tizen_files += files('security.c')
diff --git a/src/libds-tizen/util/security.c b/src/libds-tizen/util/security.c
new file mode 100644 (file)
index 0000000..735caf5
--- /dev/null
@@ -0,0 +1,162 @@
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+#include "libds/log.h"
+
+#include "util.h"
+
+#ifdef HAVE_CYNARA
+#include <cynara-session.h>
+#include <cynara-client.h>
+#include <cynara-creds-socket.h>
+#include <sys/smack.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+#define CYNARA_BUFSIZE 128
+
+static cynara *g_cynara = NULL;
+static int g_cynara_refcount = 0;
+
+static void
+__security_log_print(int err, const char *fmt, ...)
+{
+    int ret;
+    va_list args;
+    char buf[CYNARA_BUFSIZE] = "\0";
+    char tmp[CYNARA_BUFSIZE + CYNARA_BUFSIZE] = "\0";
+
+    if (fmt) {
+        va_start(args, fmt);
+        vsnprintf(tmp, CYNARA_BUFSIZE + CYNARA_BUFSIZE, fmt, args);
+        va_end(args);
+    }
+
+    ret = cynara_strerror(err, buf, CYNARA_BUFSIZE);
+    if (ret != CYNARA_API_SUCCESS) {
+        ds_err("Failed to get cynara_strerror. error : %d (error log about %s: %d)\n", ret, tmp, err);
+        return;
+    }
+
+    ds_err("%s is failed. (%s)\n", tmp, buf);
+}
+#endif
+
+bool
+tizen_security_check_privilege(pid_t pid, uid_t uid, const char *privilege)
+{
+#ifdef HAVE_CYNARA
+    bool res = false;
+    char *client_smack = NULL;
+    char *client_session = NULL;
+    char uid_str[16] = { 0, };
+    int len = -1;
+    int ret = -1;
+
+    /* If cynara_initialize() has been (retried) and failed, we suppose that cynara is not available. */
+    /* Then we return true as if there is no security check available. */
+    if (!g_cynara)
+        return true;
+
+    if (!g_cynara) {
+        ds_err("security has not been initialized.\n");
+        return false;
+    }
+
+    ret = smack_new_label_from_process((int)pid, &client_smack);
+    if (ret <= 0)
+        goto finish;
+
+    snprintf(uid_str, 15, "%d", (int)uid);
+
+    client_session = cynara_session_from_pid(pid);
+    if (!client_session)
+        goto finish;
+
+    ret = cynara_check(g_cynara, client_smack, client_session,
+                uid_str, privilege);
+
+    if (ret == CYNARA_API_ACCESS_ALLOWED)
+        res = true;
+    else
+        __security_log_print(ret, "privilege: %s, client_smack: %s, pid: %d", privilege, client_smack, pid);
+
+finish:
+    ds_dbg("Privilege Check For '%s' %s pid:%u uid:%u client_smack:%s(len:%d) client_session:%s ret:%d",
+            privilege, res ? "SUCCESS" : "FAIL", pid, uid,
+            client_smack ? client_smack : "N/A", len,
+            client_session ? client_session: "N/A", ret);
+
+    if (client_session)
+        free(client_session);
+    if (client_smack)
+        free(client_smack);
+
+    return res;
+#else
+    return true;
+#endif
+}
+
+int
+tizen_security_init(void)
+{
+#ifdef HAVE_CYNARA
+    int ret = CYNARA_API_SUCCESS;
+    int retry_cnt = 0;
+    static bool retried = false;
+
+    if (++g_cynara_refcount != 1)
+        return g_cynara_refcount;
+
+    if (!g_cynara && false == retried) {
+        retried = true;
+
+        for (retry_cnt = 0; retry_cnt < 5; retry_cnt++) {
+            ds_dbg("Retry cynara initialize: %d\n", retry_cnt + 1);
+
+            ret = cynara_initialize(&g_cynara, NULL);
+
+            if (CYNARA_API_SUCCESS == ret) {
+                ds_dbg("Succeed to initialize cynara !\n");
+                return 1;
+            }
+
+            __security_log_print(ret, "cynara_initialize");
+            g_cynara = NULL;
+        }
+    }
+
+    ds_err("Failed to initialize _security ! (error:%d, retry_cnt=%d)\n",
+        ret, retry_cnt);
+    --g_cynara_refcount;
+
+    return 0;
+#else
+    return 1;
+#endif
+}
+
+void
+tizen_security_finish(void)
+{
+#ifdef HAVE_CYNARA
+    if (g_cynara_refcount < 1) {
+        ds_err("%s called without tizen_security_init\n", __FUNCTION__);
+        return 0;
+    }
+
+    if (--g_cynara_refcount != 0)
+        return 1;
+
+    if (g_cynara) {
+        cynara_finish(g_cynara);
+        g_cynara = NULL;
+    }
+#endif
+
+    return 1;
+}
+