Merge branch 'tizen_3.0' into tizen
[sdk/target/sdbd.git] / src / sdb.c
index a07a881..5c6b2d5 100755 (executable)
--- a/src/sdb.c
+++ b/src/sdb.c
@@ -31,6 +31,7 @@
 #include <tzplatform_config.h>
 #include <pthread.h>
 #include <dlfcn.h>
+#include <sys/smack.h>
 
 #include "sysdeps.h"
 #include "log.h"
@@ -58,6 +59,7 @@
 
 #define PROC_CMDLINE_PATH "/proc/cmdline"
 #define USB_SERIAL_PATH "/sys/class/usb_mode/usb0/iSerial"
+#define APPID2PID_PATH  "/usr/bin/appid2pid"
 
 #include <sys/ioctl.h>
 #include <net/if.h>
@@ -71,6 +73,8 @@ SDB_MUTEX_DEFINE( D_lock );
 #endif
 
 int HOST = 0;
+
+// sdk user
 uid_t g_sdk_user_id;
 gid_t g_sdk_group_id;
 char* g_sdk_home_dir = NULL;
@@ -79,6 +83,12 @@ pcap g_capabilities;
 int rootshell_mode; // 0: sdk user, 1: root
 int booting_done; // 0: platform booting is in progess 1: platform booting is done
 
+// root user
+uid_t g_root_user_id;
+gid_t g_root_group_id;
+char* g_root_home_dir = NULL;
+char* g_root_home_dir_env = NULL;
+
 struct group_info
 {
     const char *name;
@@ -91,6 +101,7 @@ struct group_info g_default_groups[] = {
     {"log", -1},
     {NULL, -1}
 };
+
 #define SDB_DEFAULT_GROUPS_CNT  ((sizeof(g_default_groups)/sizeof(g_default_groups[0]))-1)
 
 int is_init_sdk_userinfo = 0;
@@ -125,6 +136,29 @@ int is_emulator(void) {
 #endif
 }
 
+int is_appid2pid_supported(void) {
+
+    if (access(APPID2PID_PATH, F_OK) == 0) {
+        /* It is necessary to confirm that it is possible
+         * to run "appid2pid" in the sdk user/group privileges. */
+        struct stat st;
+        if (stat(APPID2PID_PATH, &st) == 0) {
+            D("appid2pid uid=%d, gid=%d, mode=0x%x.\n", st.st_uid, st.st_gid, st.st_mode);
+            if ( (st.st_uid == STATIC_SDK_USER_ID && st.st_mode & S_IXUSR)
+                || (st.st_gid == STATIC_SDK_GROUP_ID && st.st_mode & S_IXGRP)
+                || (st.st_mode & S_IXOTH) ) {
+                D("appid2pid is supported.\n");
+                return 1;
+            }
+        }
+    } else {
+        D("failed to access appid2pid file: %d\n", errno);
+    }
+
+    D("appid2pid is NOT supported.\n");
+    return 0;
+}
+
 int is_container_enabled(void) {
     bool value;
     int ret;
@@ -373,7 +407,7 @@ void print_packet(const char *label, apacket *p)
 #endif
 
 #ifdef SUPPORT_ENCRYPT
-/* 
+/*
 desc. : 암호화 실패 메시지 전송
 parameter : [in] apacket* p : sdbd로 들어온 메시지
                        [in] atransport *t : 현재 연결에 대한 atransport
@@ -389,7 +423,7 @@ void send_encr_fail(apacket* p, atransport *t, unsigned failed_value){
        //put_apacket(enc_p);
 }
 
-/* 
+/*
 desc. : 암호화 메시지 핸들링
 parameter : [in] apacket* p : sdbd로 들어온 메시지
                        [in/out] atransport *t : 현재 연결에 대한 atransport
@@ -403,12 +437,12 @@ int handle_encr_packet(apacket* p, atransport *t){
 
        if(p->msg.arg0 == ENCR_SET_ON_REQ){ // hello 메시지인 경우
                t->sessionID = sessionID;
-               if((retVal = security_init(t->sessionID, NULL)) == 1){ // 암호화 handshaking을 위한 init                  
+               if((retVal = security_init(t->sessionID, NULL)) == 1){ // 암호화 handshaking을 위한 init
                        if(security_parse_server_hello(t->sessionID, p) == 1){ // hello 메시지 파싱
                                D("security_parse_server_hello success\n");
                 enc_p = get_apacket();
                                if(security_gen_client_hello(t->sessionID, enc_p) == 1){ // hello 메시지 생성
-                                       D("security_gen_client_hello success\n");                               
+                                       D("security_gen_client_hello success\n");
                                        enc_p->msg.command = A_ENCR;
                                        enc_p->msg.arg0 = ENCR_SET_ON_REQ;
                                        enc_p->msg.arg1 = p->msg.arg1;
@@ -419,7 +453,7 @@ int handle_encr_packet(apacket* p, atransport *t){
                                        D("security_gen_client_hello error\n");
                                        send_encr_fail(p, t, ENCR_ON_FAIL); // 암호화 on 실패 메시지 전송
                                        t->encryption = ENCR_OFF; // 암호화 모드는 off
-                                       security_deinit(t->sessionID);                          
+                                       security_deinit(t->sessionID);
                                        return -1;
                                }
                        }
@@ -428,7 +462,7 @@ int handle_encr_packet(apacket* p, atransport *t){
                                send_encr_fail(p, t, ENCR_ON_FAIL);
                                t->encryption = ENCR_OFF;
                                security_deinit(t->sessionID);
-                               
+
                                return -1;
                        }
                } else { // init 실패
@@ -511,7 +545,7 @@ int handle_encr_packet(apacket* p, atransport *t){
        }
        //put_apacket(enc_p);
        return 0;
-       
+
 }
 #endif
 
@@ -1540,40 +1574,40 @@ void register_bootdone_cb() {
        }
 }
 
-static int sdbd_set_groups() {
+static int sdbd_set_groups(const char *name, int gid, struct group_info default_groups[], int default_groups_size) {
     gid_t *group_ids = NULL;
     int ngroups = 0;
     int i, j = 0;
     int group_match = 0;
     int added_group_cnt = 0;
 
-    getgrouplist(SDK_USER_NAME, g_sdk_group_id, NULL, &ngroups);
+    getgrouplist(name, gid, NULL, &ngroups);
     D("group list : ngroups = %d\n", ngroups);
-    group_ids = malloc((ngroups + SDB_DEFAULT_GROUPS_CNT) * sizeof(gid_t));
+    group_ids = malloc((ngroups + default_groups_size) * sizeof(gid_t));
     if (group_ids == NULL) {
-        D("failed to allocate group_ids(%d)\n", (ngroups + SDB_DEFAULT_GROUPS_CNT) * sizeof(gid_t));
+        D("failed to allocate group_ids(%d)\n", (ngroups + default_groups_size) * sizeof(gid_t));
         return -1;
     }
-    if (getgrouplist(SDK_USER_NAME, g_sdk_group_id, group_ids, &ngroups) == -1) {
+    if (getgrouplist(name, gid, group_ids, &ngroups) == -1) {
         D("failed to getgrouplist(), ngroups = %d\n", ngroups);
         free(group_ids);
         return -1;
     }
-
-    for (i = 0; g_default_groups[i].name != NULL; i++) {
-        for (j = 0; j < ngroups; j++) {
-            if (group_ids[j] == g_default_groups[i].gid) {
-                group_match = 1;
-                break;
+    if(default_groups_size >= 1) {
+        for (i = 0; default_groups[i].name != NULL; i++) {
+            for (j = 0; j < ngroups; j++) {
+                if (group_ids[j] == default_groups[i].gid) {
+                    group_match = 1;
+                    break;
+                }
             }
+            if (group_match == 0 && default_groups[i].gid != -1) {
+                group_ids[ngroups + added_group_cnt] = default_groups[i].gid;
+                added_group_cnt ++;
+            }
+            group_match = 0;
         }
-        if (group_match == 0 && g_default_groups[i].gid != -1) {
-            group_ids[ngroups + added_group_cnt] = g_default_groups[i].gid;
-            added_group_cnt ++;
-        }
-        group_match = 0;
     }
-
     if (setgroups(ngroups+added_group_cnt, group_ids) != 0) {
         D("failed to setgroups().\n");
         free(group_ids);
@@ -1620,13 +1654,25 @@ static int sdbd_get_group(const char* group_name, struct group* grp, char* buf,
     return 0;
 }
 
-int set_sdk_user_privileges() {
+int set_sdk_user_privileges(int is_drop_capability_after_fork) {
     if (!is_init_sdk_userinfo) {
         D("failed to init sdk user information.\n");
         return -1;
     }
 
-    if (sdbd_set_groups() < 0) {
+    /*
+    * If a process switches its real, effective, or saved uids from at least one being 0 to all being non-zero,
+    * then both the permitted and effective capabilities are cleared.
+    */
+    if(is_drop_capability_after_fork) {
+
+        if (setuid(g_root_user_id) != 0) {
+            D("set root user id failed (errno: %d)\n", errno);
+            return -1;
+        }
+    }
+
+    if (sdbd_set_groups(SDK_USER_NAME, g_sdk_group_id, g_default_groups, SDB_DEFAULT_GROUPS_CNT) < 0) {
         D("set groups failed (errno: %d)\n", errno);
         return -1;
     }
@@ -1639,6 +1685,9 @@ int set_sdk_user_privileges() {
     if (setuid(g_sdk_user_id) != 0) {
         D("set user id failed (errno: %d)\n", errno);
         return -1;
+//        if(is_drop_capability_after_fork) {
+//            return -1;
+//        }
     }
 
     if (chdir(g_sdk_home_dir) < 0) {
@@ -1653,6 +1702,32 @@ int set_sdk_user_privileges() {
     return 0;
 }
 
+int set_root_privileges() {
+
+    if (sdbd_set_groups(ROOT_USER_NAME, g_root_group_id, NULL, 0) < 0) {
+        D("set root groups failed (errno: %d)\n", errno);
+    }
+
+    if (setgid(g_root_group_id) != 0) {
+        D("set root group id failed (errno: %d)\n", errno);
+    }
+
+    if (setuid(g_root_user_id) != 0) {
+        D("set root user id failed (errno: %d)\n", errno);
+    }
+
+    if (chdir(g_root_home_dir) < 0) {
+        D("unable to change root working directory to %s\n", g_sdk_home_dir);
+    }
+
+    // TODO: use pam later
+    if (g_root_home_dir_env) {
+        putenv(g_root_home_dir_env);
+    }
+
+    return 0;
+}
+
 #define SDB_PW_GR_DEFAULT_SIZE  (16*1024)
 static long get_passwd_bufsize() {
     long bufsize = 0;
@@ -1702,12 +1777,53 @@ static int init_sdb_default_groups() {
     return 0;
 }
 
-static void set_static_userinfo() {
+static void set_static_root_userinfo() {
+    g_root_user_id = STATIC_ROOT_USER_ID;
+    g_root_group_id = STATIC_ROOT_GROUP_ID;
+    g_root_home_dir = STATIC_ROOT_HOME_DIR;
+}
+
+static void set_static_sdk_userinfo() {
     g_sdk_user_id = STATIC_SDK_USER_ID;
     g_sdk_group_id = STATIC_SDK_GROUP_ID;
     g_sdk_home_dir = STATIC_SDK_HOME_DIR;
 }
 
+static int init_root_userinfo() {
+    struct passwd pwd;
+    char *buf = NULL;
+    long bufsize = 0;
+
+    bufsize = get_passwd_bufsize();
+    buf = malloc(bufsize);
+    if (buf == NULL) {
+        D("failed to allocate passwd buf(%ld)\n", bufsize);
+        set_static_root_userinfo();
+    } else {
+        if (sdbd_get_user_pwd(ROOT_USER_NAME, &pwd, buf, bufsize) < 0) {
+            D("failed to get root user passwd info.(errno: %d)\n", errno);
+            set_static_root_userinfo();
+        } else {
+            D("username=%s, uid=%d, gid=%d, dir=%s\n", pwd.pw_name, pwd.pw_uid, pwd.pw_gid, pwd.pw_dir);
+
+            g_root_user_id = pwd.pw_uid;
+            g_root_group_id = pwd.pw_gid;
+            g_root_home_dir = strdup(pwd.pw_dir);
+        }
+        free(buf);
+    }
+
+    int env_size = strlen("HOME=") + strlen(g_root_home_dir) + 1;
+    g_root_home_dir_env = malloc(env_size);
+    if(g_root_home_dir_env == NULL) {
+        D("failed to allocate for home dir env string\n");
+    } else {
+        snprintf(g_root_home_dir_env, env_size, "HOME=%s", g_root_home_dir);
+    }
+
+    return 0;
+}
+
 static int init_sdk_userinfo() {
     struct passwd pwd;
     char *buf = NULL;
@@ -1725,11 +1841,11 @@ static int init_sdk_userinfo() {
     buf = malloc(bufsize);
     if (buf == NULL) {
         D("failed to allocate passwd buf(%ld)\n", bufsize);
-        set_static_userinfo();
+        set_static_sdk_userinfo();
     } else {
         if (sdbd_get_user_pwd(SDK_USER_NAME, &pwd, buf, bufsize) < 0) {
             D("get user passwd info.(errno: %d)\n", errno);
-            set_static_userinfo();
+            set_static_sdk_userinfo();
         } else {
             D("username=%s, uid=%d, gid=%d, dir=%s\n", pwd.pw_name, pwd.pw_uid, pwd.pw_gid, pwd.pw_dir);
 
@@ -1766,6 +1882,7 @@ static void init_sdk_requirements() {
     }
 
     init_sdk_userinfo();
+    init_root_userinfo();
 
     if (g_sdk_home_dir != NULL && stat(g_sdk_home_dir, &st) == 0) {
         if (st.st_uid != g_sdk_user_id || st.st_gid != g_sdk_group_id) {
@@ -1848,6 +1965,9 @@ static void init_capabilities(void) {
                     "%s", DISABLED);
     }
 
+    // Sdbd root permission
+    snprintf(g_capabilities.root_permission, sizeof(g_capabilities.root_permission),
+                "%s", DISABLED);
 
     // Root command support
     if(!request_capability_to_plugin(CAPABILITY_ROOT_ONOFF, g_capabilities.rootonoff_support,
@@ -2000,6 +2120,19 @@ static void init_capabilities(void) {
                        "%s", UNKNOWN);
     }
 
+    // appid2pid support
+    ret = is_appid2pid_supported();
+    snprintf(g_capabilities.appid2pid_support, sizeof(g_capabilities.appid2pid_support),
+                "%s", ret == 1 ? ENABLED : DISABLED);
+
+    // pkgcmd debug mode support
+    if(!request_capability_to_plugin(CAPABILITY_DEBUGMODE, g_capabilities.pkgcmd_debugmode,
+                sizeof(g_capabilities.pkgcmd_debugmode))) {
+        D("failed to request. (%d:%d) \n", PLUGIN_SYNC_CMD_CAPABILITY, CAPABILITY_DEBUGMODE);
+        snprintf(g_capabilities.pkgcmd_debugmode, sizeof(g_capabilities.pkgcmd_debugmode),
+                "%s", ENABLED);
+    }
+
     // Capability version
     snprintf(g_capabilities.sdbd_cap_version, sizeof(g_capabilities.sdbd_cap_version),
                 "%d.%d", SDBD_CAP_VERSION_MAJOR, SDBD_CAP_VERSION_MINOR);