shell: introduce sdb user daemon for user shell
[sdk/target/sdbd.git] / src / services.c
index 2e1b577..f395fca 100644 (file)
@@ -39,6 +39,8 @@
 #   include <sys/inotify.h>
 #   include "sdktools.h"
 #endif
+#include <sys/socket.h>
+#include <sys/un.h>
 
 #include "strutils.h"
 #include "utils.h"
@@ -147,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")) {
@@ -376,106 +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;
 }
 
 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;
-    }
-
-    if (smack_setlabel(devname, SDK_SHELL_LABEL_NAME, SMACK_LABEL_ACCESS) == -1) {
-        D("unable to set sdk shell smack label %s due to (errno:%d)\n", SDK_SHELL_LABEL_NAME, 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_validity_to_plugin(PLUGIN_SYNC_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 {
-                if (getuid() != g_sdk_user_id && set_sdk_user_privileges() < 0) {
-                    fprintf(stderr, "failed to set SDK user privileges\n");
+                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-user"
+#define SHELL_COMMAND "/usr/sbin/sdbd-user"
 #define LOGIN_COMMAND "/bin/login"
 #define SUPER_USER    "root"
 #define LOGIN_CONFIG  "/etc/login.defs"
@@ -489,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)) {
@@ -877,83 +909,87 @@ 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);
+            "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);
+            "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);
+            "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);
 
     // Capability version
     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
-                                "sdbd_cap_version", g_capabilities.sdbd_cap_version);
+            "sdbd_cap_version", g_capabilities.sdbd_cap_version);
 
     // Sdbd log enable
     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
@@ -963,20 +999,17 @@ static void get_capability(int fd, void *cookie) {
     offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
             "log_path", g_capabilities.log_path);
 
-    offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
-            "pkgcmd_debugmode", g_capabilities.pkgcmd_debugmode);
-
     // 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);
+            "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);
+            "pkgcmd_debugmode", g_capabilities.pkgcmd_debugmode);
 
     offset++; // for '\0' character