shell: introduce sdb user daemon for user shell
[sdk/target/sdbd.git] / src / services.c
index 2672394..f395fca 100644 (file)
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#include <stdlib.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
 #include <errno.h>
@@ -24,6 +24,8 @@
 #include "sysdeps.h"
 
 #define  TRACE_TAG  TRACE_SERVICES
+#include "log.h"
+
 #include "sdb.h"
 #include "file_sync_service.h"
 
 #   include <sys/inotify.h>
 #   include "sdktools.h"
 #endif
+#include <sys/socket.h>
+#include <sys/un.h>
 
 #include "strutils.h"
 #include "utils.h"
 #include <system_info.h>
 #include <tzplatform_config.h>
+#include <sys/smack.h>
 
 #include <vconf.h>
 #include <limits.h>
 #include <termios.h>
 #include <sys/ioctl.h>
 
+#include "sdbd_plugin.h"
+#include "plugin.h"
+
+#define ENV_BUF_MAX     4096
+
 typedef struct stinfo stinfo;
 
 struct stinfo {
@@ -57,7 +67,6 @@ struct stinfo {
     void *cookie;
 };
 
-
 void *service_bootstrap_func(void *x)
 {
     stinfo *sti = x;
@@ -90,7 +99,7 @@ static void dns_service(int fd, void *cookie)
 
 static int is_support_interactive_shell()
 {
-    return (!strncmp(g_capabilities.intershell_support, SDBD_CAP_RET_ENABLED, strlen(SDBD_CAP_RET_ENABLED)));
+    return (!strncmp(g_capabilities.intershell_support, PLUGIN_RET_ENABLED, strlen(PLUGIN_RET_ENABLED)));
 }
 
 #if 0
@@ -127,55 +136,11 @@ static void recover_service(int s, void *cookie)
     sdb_close(fd);
 }
 
-void restart_root_service(int fd, void *cookie)
-{
-    char buf[100];
-    char value[PROPERTY_VALUE_MAX];
-
-    if (getuid() == 0) {
-        snprintf(buf, sizeof(buf), "sdbd is already running as root\n");
-        writex(fd, buf, strlen(buf));
-        sdb_close(fd);
-    } else {
-        property_get("ro.debuggable", value, "");
-        if (strcmp(value, "1") != 0) {
-            snprintf(buf, sizeof(buf), "sdbd cannot run as root in production builds\n");
-            writex(fd, buf, strlen(buf));
-            sdb_close(fd);
-            return;
-        }
-
-        property_set("service.sdb.root", "1");
-        snprintf(buf, sizeof(buf), "restarting sdbd as root\n");
-        writex(fd, buf, strlen(buf));
-        sdb_close(fd);
-    }
-}
 #endif
 
-void restart_tcp_service(int fd, void *cookie)
-{
-    char buf[100];
-    char value[PROPERTY_VALUE_MAX];
-    int port = (int)cookie;
-
-    if (port <= 0) {
-        snprintf(buf, sizeof(buf), "invalid port\n");
-        writex(fd, buf, strlen(buf));
-        sdb_close(fd);
-        return;
-    }
-
-    snprintf(value, sizeof(value), "%d", port);
-    property_set("service.sdb.tcp.port", value);
-    snprintf(buf, sizeof(buf), "restarting in TCP mode port: %d\n", port);
-    writex(fd, buf, strlen(buf));
-    sdb_close(fd);
-}
-
 static int is_support_rootonoff()
 {
-    return (!strncmp(g_capabilities.rootonoff_support, SDBD_CAP_RET_ENABLED, strlen(SDBD_CAP_RET_ENABLED)));
+    return (!strncmp(g_capabilities.rootonoff_support, PLUGIN_RET_ENABLED, strlen(PLUGIN_RET_ENABLED)));
 }
 
 void rootshell_service(int fd, void *cookie)
@@ -184,24 +149,17 @@ void rootshell_service(int fd, void *cookie)
     char *mode = (char*) cookie;
 
     if (!strcmp(mode, "on")) {
-        if (getuid() == 0) {
-            if (rootshell_mode == 1) {
-                //snprintf(buf, sizeof(buf), "Already changed to sdk user mode\n");
-                // do not show message
+        if (rootshell_mode == 1) {
+            //snprintf(buf, sizeof(buf), "Already changed to sdk user mode\n");
+            // do not show message
+        } else {
+            if (is_support_rootonoff()) {
+                rootshell_mode = 1;
+                //allows a permitted user to execute a command as the superuser
+                snprintf(buf, sizeof(buf), "Switched to 'root' account mode\n");
             } else {
-                if (is_support_rootonoff()) {
-                    rootshell_mode = 1;
-                    //allows a permitted user to execute a command as the superuser
-                    snprintf(buf, sizeof(buf), "Switched to 'root' account mode\n");
-                } else {
-                    snprintf(buf, sizeof(buf), "Permission denied\n");
-                }
-                writex(fd, buf, strlen(buf));
+                snprintf(buf, sizeof(buf), "Permission denied\n");
             }
-        } else {
-            D("need root permission for root shell: %d\n", getuid());
-            rootshell_mode = 0;
-            snprintf(buf, sizeof(buf), "Permission denied\n");
             writex(fd, buf, strlen(buf));
         }
     } else if (!strcmp(mode, "off")) {
@@ -219,13 +177,32 @@ void rootshell_service(int fd, void *cookie)
     sdb_close(fd);
 }
 
-void restart_usb_service(int fd, void *cookie)
-{
-    char buf[100];
+enum tzplatform_get_env_error_status {
+    NO_ERROR_TZPLATFORM_ENV = 0,
+    ERROR_TZPLATFORM_ENV_GENERAL = 1,
+    ERROR_TZPLATFORM_ENV_INVALID_VARIABLES = 2,
+};
 
-    property_set("service.sdb.tcp.port", "0");
-    snprintf(buf, sizeof(buf), "restarting in USB mode\n");
+void get_tzplatform_env(int fd, void *cookie) {
+    char buf[PATH_MAX] = { 0, };
+    char *env_name = (char*) cookie;
+    D("environment variable name: %s\n", env_name);
+    enum tzplatform_variable env_id = tzplatform_getid(env_name);
+    if (env_id != _TZPLATFORM_VARIABLES_INVALID_) {
+        const char *env_value = tzplatform_getenv(env_id);
+        if (env_value) {
+            D("environment value : %s\n", env_value);
+            snprintf(buf, sizeof(buf), "%d%s", NO_ERROR_TZPLATFORM_ENV, env_value);
+        } else {
+            D("failed to get environment value using tzplatform_getenv");
+            snprintf(buf, sizeof(buf), "%d", ERROR_TZPLATFORM_ENV_GENERAL);
+        }
+    } else {
+        D("environment name (%s) is invalid\n", env_name);
+        snprintf(buf, sizeof(buf), "%d", ERROR_TZPLATFORM_ENV_INVALID_VARIABLES);
+    }
     writex(fd, buf, strlen(buf));
+    free(env_name);
     sdb_close(fd);
 }
 
@@ -277,6 +254,7 @@ void inoti_service(int fd, void *arg)
 
     if ( ifd < 0 ) {
         D( "inotify_init failed\n");
+        sdb_close(fd);
         return;
     }
 
@@ -302,12 +280,13 @@ void inoti_service(int fd, void *arg)
                 if (event->mask & IN_CREATE) {
                     if (!(event->mask & IN_ISDIR)) {
                         char *cspath = NULL;
-                        int len = asprintf(&cspath, "%s/%s", CS_PATH,
-                                event->name);
-                        D( "The file %s was created.\n", cspath);
-                        writex(fd, cspath, len);
-                        if (cspath != NULL) {
+                        int len = asprintf(&cspath, "%s/%s", CS_PATH, event->name);
+                        if (len >= 0) {
+                            D( "The file %s was created.\n", cspath);
+                            writex(fd, cspath, len);
                             free(cspath);
+                        } else {
+                            D( "asprintf was failed\n" );
                         }
                     }
                 }
@@ -392,97 +371,142 @@ static int create_service_thread(void (*func)(int, void *), void *cookie)
 }
 
 #if !SDB_HOST
-
-static void redirect_and_exec(int pts, const char *cmd, char * const argv[], char * const envp[])
+/* receive the ptm from child, sdbd-user */
+static ssize_t recv_fd(int fd, void *ptr, size_t nbytes, int *recvfd)
 {
-    dup2(pts, 0);
-    dup2(pts, 1);
-    dup2(pts, 2);
+    struct msghdr msg;
+    struct iovec iov[1];
+    struct cmsghdr *pheader;
+    union {
+        struct cmsghdr cmhdr;
+        char control[CMSG_SPACE(sizeof(int))];
+    } control_un;
+    ssize_t ret;
+
+    msg.msg_control = control_un.control;
+    msg.msg_controllen = sizeof(control_un.control);
+
+    msg.msg_name = NULL;
+    msg.msg_namelen = 0;
+
+    iov[0].iov_base = ptr;
+    iov[0].iov_len = nbytes;
+    msg.msg_iov = iov;
+    msg.msg_iovlen = 1;
+
+    if ((ret = recvmsg(fd, &msg, 0)) <= 0) {
+        return ret;
+    }
 
-    sdb_close(pts);
+    if ((pheader = CMSG_FIRSTHDR(&msg)) != NULL &&
+            pheader->cmsg_len == CMSG_LEN(sizeof(int))) {
+        if (pheader->cmsg_level != SOL_SOCKET) {
+            D("sdb: control level != SOL_SOCKET");
+            exit(-1);
+        }
+        if (pheader->cmsg_type != SCM_RIGHTS) {
+            D("sdb: control type != SCM_RIGHTS");
+            exit(-1);
+        }
+        memcpy(recvfd, CMSG_DATA(pheader), sizeof(int));
+    } else {
+        *recvfd = -1;
+    }
 
-    execve(cmd, argv, envp);
+    return ret;
 }
 
-static int create_subprocess(const char *cmd, pid_t *pid, char * const argv[], char * const envp[])
+int create_subprocess(const char *cmd, pid_t *pid, char * const argv[], char * const envp[])
 {
-    char devname[64];
-    int ptm;
-
-    ptm = unix_open("/dev/ptmx", O_RDWR); // | O_NOCTTY);
-    if(ptm < 0){
-        D("[ cannot open /dev/ptmx - errno:%d ]\n",errno);
-        return -1;
-    }
-    if (fcntl(ptm, F_SETFD, FD_CLOEXEC) < 0) {
-        D("[ cannot set cloexec to /dev/ptmx - errno:%d ]\n",errno);
-    }
-
-    if(grantpt(ptm) || unlockpt(ptm) ||
-        ptsname_r(ptm, devname, sizeof(devname)) != 0 ){
-        D("[ trouble with /dev/ptmx - errno:%d ]\n", errno);
-        sdb_close(ptm);
-        return -1;
-    }
-
     *pid = fork();
     if(*pid < 0) {
         D("- fork failed: errno:%d -\n", errno);
-        sdb_close(ptm);
         return -1;
     }
 
-    if(*pid == 0){
-        int pts;
-
-        setsid();
-
-        pts = unix_open(devname, O_RDWR);
-        if(pts < 0) {
-            fprintf(stderr, "child failed to open pseudo-term slave: %s\n", devname);
-            exit(-1);
-        }
-
-        sdb_close(ptm);
-
-        // set OOM adjustment to zero
-        {
-            char text[64];
-            //snprintf(text, sizeof text, "/proc/%d/oom_score_adj", getpid());
-            snprintf(text, sizeof text, "/proc/%d/oom_adj", getpid());
-            int fd = sdb_open(text, O_WRONLY);
-            if (fd >= 0) {
-                sdb_write(fd, "0", 1);
-                sdb_close(fd);
-            } else {
-               // FIXME: not supposed to be here
-               D("sdb: unable to open %s due to errno:%d\n", text, errno);
-            }
-        }
-
+    if (*pid == 0) {
         if (should_drop_privileges()) {
-            if (argv[2] != NULL && getuid() == 0 && request_plugin_verification(SDBD_CMD_VERIFY_ROOTCMD, argv[2])) {
+            if (argv[2] != NULL && request_validity_to_plugin(PLUGIN_SYNC_CMD_VERIFY_ROOTCMD, argv[2])) {
                 // do nothing
                 D("sdb: executes root commands!!:%s\n", argv[2]);
             } else {
-                set_sdk_user_privileges();
+                if (getuid() != g_sdk_user_id && set_sdk_user_privileges(RESERVE_CAPABILITIES_AFTER_FORK) < 0) {
+                    D("failed to set SDK user privileges\n");
+                    exit(-1);
+                }
             }
+        } else {
+            set_root_privileges();
         }
-        redirect_and_exec(pts, cmd, argv, envp);
-        fprintf(stderr, "- exec '%s' failed: (errno:%d) -\n",
-                cmd, errno);
+        /* exec sdbduser */
+        execve(cmd, argv, envp);
+        D("- exec '%s' failed: (errno:%d) -\n", cmd, errno);
         exit(-1);
     } else {
         // Don't set child's OOM adjustment to zero.
         // Let the child do it itself, as sometimes the parent starts
         // running before the child has a /proc/pid/oom_adj.
         // """sdb: unable to open /proc/644/oom_adj""" seen in some logs.
+        char tmptext[32];
+        int ptm = -1;
+        struct sockaddr_un addr;
+        int sock;
+        int trycnt = 1;
+
+        /* The child process will open .sdbduser_pid.sock socket.
+           This socket transfers the ptm fd that was opened by child process.
+           You can see related code on subprocess.c file. */
+        snprintf(tmptext, sizeof tmptext, "/tmp/.sdbduser_%d.sock", (int)(*pid));
+        char *sockpath = strdup(tmptext);
+        if (sockpath == NULL) {
+            D("failed to get socket path, %s\n", strerror(errno));
+            return -1;
+        }
+        D("read fd socket is %s\n", sockpath);
+
+        sock = socket(PF_LOCAL, SOCK_STREAM, 0);
+        if (sock == -1) {
+            D("socket error, %s\n", strerror(errno));
+            free(sockpath);
+            return -1;
+        }
+        memset(&addr, 0, sizeof(addr));
+        addr.sun_family = AF_LOCAL;
+        strcpy(addr.sun_path, sockpath);
+        int slen = offsetof(struct sockaddr_un, sun_path) + strlen(sockpath);
+        while (connect(sock, (struct sockaddr *)&addr, slen) == -1
+                && trycnt < 100) {
+            D("try to connect socket %s, %d times.\n", sockpath, trycnt++);
+            /* sleep maximum 100 times */
+            usleep(10000);
+        }
+        if (trycnt == 100) {
+            D("failed to connect, err: %s\n", strerror(errno));
+            free(sockpath);
+            return -1;
+        }
+
+        char c;
+        if (recv_fd(sock, &c, 1, &ptm) == -1) {
+            D("recv_fd error, %s\n", strerror(errno));
+            free(sockpath);
+            return -1;
+        } else {
+            D("got ptm fd from child, fd: %d\n", ptm);
+        }
+
+        if (sdb_close(sock) == -1) {
+            D("close sock error, %s\n", strerror(errno));
+        }
+        free(sockpath);
+
+        D("getting child's ptm successed.\n");
         return ptm;
     }
 }
 #endif  /* !SDB_HOST */
 
-#define SHELL_COMMAND "/bin/sh"
+#define SHELL_COMMAND "/usr/sbin/sdbd-user"
 #define LOGIN_COMMAND "/bin/login"
 #define SUPER_USER    "root"
 #define LOGIN_CONFIG  "/etc/login.defs"
@@ -496,6 +520,7 @@ static void subproc_waiter_service(int fd, void *cookie)
     for (;;) {
         int status;
         pid_t p = waitpid(pid, &status, 0);
+        D("entered fd=%d, post waitpid(pid=%d)\n", fd, p);
         if (p == pid) {
             D("fd=%d, post waitpid(pid=%d) status=%04x\n", fd, p, status);
             if (WIFEXITED(status)) {
@@ -519,7 +544,7 @@ static void subproc_waiter_service(int fd, void *cookie)
     }
 }
 
-static void get_env(char *key, char **env)
+void get_env(char *key, char **env)
 {
     FILE *fp;
     char buf[1024];
@@ -535,7 +560,7 @@ static void get_env(char *key, char **env)
         e = buf + (strlen(buf) - 1);
 
         // trim string
-        while(*e == ' ' ||  *e == '\n' || *e == '\t') {
+        while( (e > s) && (*e == ' ' ||  *e == '\n' || *e == '\t')) {
             e--;
         }
         *(e+1) ='\0';
@@ -569,23 +594,20 @@ static int create_subproc_thread(const char *name, int lines, int columns)
     char *value = NULL;
     char *trim_value = NULL;
     char path[PATH_MAX];
+    char *envp[MAX_TOKENS];
+    int envp_cnt = 0;
+
     memset(path, 0, sizeof(path));
+    memset(envp, 0, sizeof(envp));
 
-    char *envp[] = {
-        "TERM=linux", /* without this, some programs based on screen can't work, e.g. top */
-        "DISPLAY=:0", /* without this, some programs based on without launchpad can't work */
-        NULL,
-        NULL,
-        NULL,
-        NULL,
-        NULL
-    };
+    envp[envp_cnt++] = strdup("TERM=linux");
+    envp[envp_cnt++] = strdup("DISPLAY=:0");
 
     if (should_drop_privileges()) {
         if (g_sdk_home_dir_env) {
-            envp[2] = g_sdk_home_dir_env;
+            envp[envp_cnt++] = strdup(g_sdk_home_dir_env);
         } else {
-            envp[2] = "HOME=/home/owner";
+            envp[envp_cnt++] = strdup("HOME=/home/owner");
         }
         get_env("ENV_PATH", &value);
     } else {
@@ -593,7 +615,7 @@ static int create_subproc_thread(const char *name, int lines, int columns)
         if(value == NULL) {
             get_env("ENV_ROOTPATH", &value);
         }
-        envp[2] = "HOME=/root";
+        envp[envp_cnt++] = strdup("HOME=/root");
     }
     if (value != NULL) {
         trim_value = str_trim(value);
@@ -604,19 +626,40 @@ static int create_subproc_thread(const char *name, int lines, int columns)
             } else {
                 snprintf(path, sizeof(path), "%s", trim_value);
             }
-            envp[3] = path;
+            envp[envp_cnt++] = strdup(path);
         } else {
             snprintf(path, sizeof(path), "%s", value);
-            envp[3] = path;
+            envp[envp_cnt++] = strdup(path);
         }
         free(value);
     }
 
-    D("path env:%s,%s,%s,%s\n", envp[0], envp[1], envp[2], envp[3]);
+    /* get environment variables from plugin */
+    char *envp_plugin = NULL;
+    envp_plugin = malloc(ENV_BUF_MAX);
+    if (envp_plugin == NULL) {
+        D("Cannot allocate the shell commnad buffer.");
+        return -1;
+    }
+    memset(envp_plugin, 0, ENV_BUF_MAX);
+    if (!request_conversion_to_plugin(PLUGIN_SYNC_CMD_GET_SHELL_ENV, NULL,
+                envp_plugin, ENV_BUF_MAX)) {
+        D("Failed to convert the shell command. (%s)\n", name);
+        free(envp_plugin);
+        return -1;
+    } else {
+       if(envp_plugin[0] != '\0') {
+            envp_cnt = tokenize_append(envp_plugin, "\n", envp, MAX_TOKENS, envp_cnt);
+        }
+    }
+    free(envp_plugin);
+
+    /* Last element of envp must be the NULL-terminator to prevent execvp fail */
+    envp[envp_cnt] = NULL;
 
     if(name) { // in case of shell execution directly
         // Check the shell command validation.
-        if (!request_plugin_verification(SDBD_CMD_VERIFY_SHELLCMD, name)) {
+        if (!request_validity_to_plugin(PLUGIN_SYNC_CMD_VERIFY_SHELLCMD, name)) {
             D("This shell command is invalid. (%s)\n", name);
             return -1;
         }
@@ -630,7 +673,7 @@ static int create_subproc_thread(const char *name, int lines, int columns)
         }
 
         memset(new_cmd, 0, SDBD_SHELL_CMD_MAX);
-        if(!request_plugin_cmd(SDBD_CMD_CONV_SHELLCMD, name, new_cmd, SDBD_SHELL_CMD_MAX)) {
+        if(!request_conversion_to_plugin(PLUGIN_SYNC_CMD_CONVERT_SHELLCMD, name, new_cmd, SDBD_SHELL_CMD_MAX)) {
             D("Failed to convert the shell command. (%s)\n", name);
             free(new_cmd);
             return -1;
@@ -680,6 +723,18 @@ static int create_subproc_thread(const char *name, int lines, int columns)
         }
 #endif
     }
+
+    /* free environment variables */
+    int i = 0;
+    if(envp_cnt > 0) {
+        for(i = 0; i < envp_cnt; i++) {
+            if(envp[i]) {
+                D("envp[%d] = %s\n", i, envp[i]);
+                free(envp[i]);
+            }
+        }
+    }
+
     D("create_subprocess() ret_fd=%d pid=%d\n", ret_fd, pid);
 
     if (ret_fd < 0) {
@@ -753,7 +808,6 @@ static int create_sync_subprocess(void (*func)(int, void *), void* cookie) {
     if(sdb_thread_create( &t, service_bootstrap_func, sti)){
         free(sti);
         sdb_close(s[0]);
-        sdb_close(s[1]);
         printf("cannot create service monitor thread\n");
         return -1;
     }
@@ -778,7 +832,6 @@ static int create_syncproc_thread()
 
     return ret_fd;
 }
-
 #endif
 
 static void get_platforminfo(int fd, void *cookie) {
@@ -856,72 +909,107 @@ static void get_capability(int fd, void *cookie) {
 
     // Secure protocol support
     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
-                                "secure_protocol", g_capabilities.secure_protocol);
+            "secure_protocol", g_capabilities.secure_protocol);
 
     // Interactive shell support
     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
-                                "intershell_support", g_capabilities.intershell_support);
+            "intershell_support", g_capabilities.intershell_support);
 
     // File push/pull support
     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
-                                "filesync_support", g_capabilities.filesync_support);
+            "filesync_support", g_capabilities.filesync_support);
 
     // USB protocol support
     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
-                                "usbproto_support", g_capabilities.usbproto_support);
+            "usbproto_support", g_capabilities.usbproto_support);
 
     // Socket protocol support
     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
-                                "sockproto_support", g_capabilities.sockproto_support);
+            "sockproto_support", g_capabilities.sockproto_support);
+
+    // Window size synchronization support
+    offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
+            "syncwinsz_support", g_capabilities.syncwinsz_support);
+
+    // sdbd root permission
+    offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
+            "sdbd_rootperm", g_capabilities.root_permission);
 
     // Root command support
     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
-                                "rootonoff_support", g_capabilities.rootonoff_support);
+            "rootonoff_support", g_capabilities.rootonoff_support);
+
+    // Encryption support
+    offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
+            "encryption_support", g_capabilities.encryption_support);
 
     // Zone support
     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
-                                "zone_support", g_capabilities.zone_support);
+            "zone_support", g_capabilities.zone_support);
 
     // Multi-User support
     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
-                                "multiuser_support", g_capabilities.multiuser_support);
+            "multiuser_support", g_capabilities.multiuser_support);
 
     // CPU Architecture of model
     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
-                                "cpu_arch", g_capabilities.cpu_arch);
+            "cpu_arch", g_capabilities.cpu_arch);
 
     // SDK Tool path
     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
-                                "sdk_toolpath", g_capabilities.sdk_toolpath);
+            "sdk_toolpath", g_capabilities.sdk_toolpath);
 
     // Profile name
     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
-                                "profile_name", g_capabilities.profile_name);
+            "profile_name", g_capabilities.profile_name);
 
     // Vendor name
     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
-                                "vendor_name", g_capabilities.vendor_name);
+            "vendor_name", g_capabilities.vendor_name);
+
+    // Target name of the launch possible
+    offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
+            "can_launch", g_capabilities.can_launch);
 
     // Platform version
     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
-                                "platform_version", g_capabilities.platform_version);
+            "platform_version", g_capabilities.platform_version);
 
     // Product version
     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
-                                "product_version", g_capabilities.product_version);
+            "product_version", g_capabilities.product_version);
 
     // Sdbd version
     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
-                                "sdbd_version", g_capabilities.sdbd_version);
+            "sdbd_version", g_capabilities.sdbd_version);
 
     // Sdbd plugin version
     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
-                                "sdbd_plugin_version", g_capabilities.sdbd_plugin_version);
+            "sdbd_plugin_version", g_capabilities.sdbd_plugin_version);
 
-    // Window size synchronization support
+    // Capability version
+    offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
+            "sdbd_cap_version", g_capabilities.sdbd_cap_version);
+
+    // Sdbd log enable
     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
-                                "syncwinsz_support", g_capabilities.syncwinsz_support);
+            "log_enable", g_capabilities.log_enable);
 
+    // Sdbd log path
+    offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
+            "log_path", g_capabilities.log_path);
+
+    // Application command support
+    offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
+            "appcmd_support", g_capabilities.appcmd_support);
+
+    // appid2pid support
+    offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
+            "appid2pid_support", g_capabilities.appid2pid_support);
+
+    // pkgcmd debug mode support
+    offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
+            "pkgcmd_debugmode", g_capabilities.pkgcmd_debugmode);
 
     offset++; // for '\0' character
 
@@ -1082,6 +1170,12 @@ int service_to_fd(const char *name)
         if(!strncmp(name+10, "syncwinsz:", 10)){
             ret = create_service_thread(sync_windowsize, (void *)name+20);
         }
+    } else if(!strncmp(name, "tzplatformenv:", 14)) {
+       char* env_variable = NULL;
+       env_variable = strdup(name+14);
+       ret = create_service_thread(get_tzplatform_env, (void *)(env_variable));
+    } else if(!strncmp(name, "appcmd:", 7)){
+        ret = request_appcmd_to_plugin(name+7);
     }
 
     if (ret >= 0) {