Implementation of automatic command exchange feature. 45/188045/4 accepted/tizen/5.0/unified/20181102.031927 accepted/tizen/unified/20180917.041255 submit/tizen/20180914.082214 submit/tizen_5.0/20181101.000009
authoradhavan.m <adhavan.m@samsung.com>
Thu, 30 Aug 2018 13:29:32 +0000 (18:59 +0530)
committerManish Rathod <manish.r@samsung.com>
Fri, 14 Sep 2018 08:20:25 +0000 (08:20 +0000)
Change-Id: Ic9a971972fe6e929332621fbe23216f6f81c6f87
Signed-off-by: adhavan.m <adhavan.m@samsung.com>
src/plugin.c
src/plugin.h
src/sdb.c
src/services.c

index 73d095e..3deabcb 100644 (file)
@@ -36,6 +36,8 @@ PLUGIN_ASYNCHRONOUS_CMD_PROC plugin_async_proc = NULL;
 
 hashtable* plugin_cmd_hashtable = NULL;
 
+char* extcmd = NULL;
+
 typedef struct _async_parameter {
     int cmd;
     parameters* in;
@@ -119,6 +121,30 @@ static int load_plugin_not_default()
     return 1;
 }
 
+void readxml() {
+    char * buffer = NULL;
+    long length;
+    FILE * fptr = fopen(PLUGIN_XML_PATH, "rb");
+
+    if (fptr == NULL) {
+        E("failed to open commands.xml\n");
+        return;
+    }
+
+    fseek(fptr, 0, SEEK_END);
+    length = ftell(fptr);
+    fseek(fptr, 0, SEEK_SET);
+    buffer = malloc(length);
+    if (buffer) {
+        fread(buffer, 1, length, fptr);
+    }
+    fclose(fptr);
+    if (buffer) {
+        D("command xml data: %s\n", buffer);
+        extcmd = buffer;
+    }
+}
+
 void load_sdbd_plugin()
 {
     int ret;
@@ -137,6 +163,7 @@ void load_sdbd_plugin()
         D ( "using sdbd plugin interface.(%s)\n", PLUGIN_PATH );
 
         plugin_init_proc ( plugin_event_handler, plugin_register_command );
+        readxml();
     }
 
     // use default plugin feature for the commands or events that are not supported by plugin
@@ -154,6 +181,11 @@ void unload_sdbd_plugin()
         dlclose ( g_plugin_handle );
         g_plugin_handle = NULL;
     }
+
+    if (extcmd) {
+        free(extcmd);
+        extcmd = NULL;
+    }
 }
 
 // return 1 if plugin support given command
@@ -265,6 +297,56 @@ static int create_async_proc_thread( int cmd, parameters* in )
     return s[0];
 }
 
+static void *async_proc_extcmd_bootstrap_func(void *x)
+{
+    async_parameter *p = x;
+    plugin_async_proc(p->cmd, p->in, p->out_fd);
+    release_parameters(p->in);
+    free(p->in);
+    sdb_close(p->out_fd);
+    free(p);
+    return 0;
+}
+
+int create_async_extcmd_proc_thread( int cmd, parameters* in )
+{
+    async_parameter* async_param;
+    sdb_thread_t t;
+    int s[2];
+
+    if (sdb_socketpair(s)) {
+        release_parameters(in);
+        free(in);
+        E("cannot create extcmd async proc socket pair\n");
+        return -1;
+    }
+
+    async_param = (async_parameter*)malloc(sizeof(async_parameter));
+    if (async_param == NULL) {
+        release_parameters(in);
+        free(in);
+        fatal("cannot allocate async_parameter");
+        return -1;
+    }
+
+    async_param->cmd = cmd;
+    async_param->in = in;
+    async_param->out_fd = s[1];
+
+    if (sdb_thread_create(&t, async_proc_extcmd_bootstrap_func, async_param)) {
+        free(async_param);
+        sdb_close(s[0]);
+        sdb_close(s[1]);
+        release_parameters(in);
+        free(in);
+        E("cannot create extcmd async proc thread\n");
+        return -1;
+    }
+
+    D("extcmd async proc thread started, %d:%d\n",s[0], s[1]);
+    return s[0];
+}
+
 // return 1 if succeed to get capability from plugin
 // return 0 otherwise
 int request_capability_to_plugin ( int cap, char* out_buf, unsigned int out_len )
@@ -335,6 +417,45 @@ int request_validity_to_plugin ( int cmd, const char* in_buf )
     return success;
 }
 
+// return 1 if allowed by plugin (valid)
+// return 0 if disallowed by plugin (invalid)
+int request_extcmd_validity_to_plugin ( int cmd, const char* in_buf)
+{
+    int success = 0;
+    int ret;
+    parameters in, out;
+
+    if ( in_buf != NULL ) {
+        in.number_of_parameter = 1;
+        in.array_of_parameter = ( parameter* ) malloc ( sizeof ( parameter ) );
+        if (in.array_of_parameter == NULL) {
+            D("failed to allocate memory for the parameter\n");
+            return success;
+        }
+        in.array_of_parameter[0].type = type_string;
+        in.array_of_parameter[0].v_string.length = strlen ( in_buf );
+        in.array_of_parameter[0].v_string.data = strdup ( in_buf );
+    } else {
+        in.number_of_parameter = 0;
+        in.array_of_parameter = NULL;
+    }
+
+    D ("requested validity : %d, %s\n", cmd, in_buf);
+
+    out.number_of_parameter = 0;
+    out.array_of_parameter = NULL;
+    ret = plugin_sync_proc ( cmd, &in, &out );
+    if ( ret == PLUGIN_CMD_SUCCESS ) {
+        success = ( out.array_of_parameter[0].v_int32 == PLUGIN_RET_VALID ) ? 1 : 0;
+        release_parameters ( &out );
+
+        D ("request validity success : %d\n", success);
+    }
+
+    release_parameters ( &in );
+    return success;
+}
+
 // return 1 if succeed to convert
 // return 0 otherwise
 int request_conversion_to_plugin ( int cmd, const char* in_buf, char* out_buf, unsigned int out_len )
@@ -370,6 +491,44 @@ int request_conversion_to_plugin ( int cmd, const char* in_buf, char* out_buf, u
     return success;
 }
 
+// return 1 if succeed to convert
+// return 0 otherwise
+int request_extcmd_conversion_to_plugin ( int cmd, const char* in_buf, char* out_buf, unsigned int out_len )
+{
+    int success = 0;
+    int ret;
+    parameters in, out;
+
+    if ( in_buf != NULL ) {
+        in.number_of_parameter = 1;
+        in.array_of_parameter = ( parameter* ) malloc ( sizeof ( parameter ) );
+        if (in.array_of_parameter == NULL) {
+            E("failed to allocate memory for the parameter\n");
+            return success;
+        }
+        in.array_of_parameter[0].type = type_string;
+        in.array_of_parameter[0].v_string.length = strlen ( in_buf );
+        in.array_of_parameter[0].v_string.data = strdup ( in_buf );
+    } else {
+        in.number_of_parameter = 0;
+        in.array_of_parameter = NULL;
+    }
+
+    out.number_of_parameter = 0;
+    out.array_of_parameter = NULL;
+
+    ret = plugin_sync_proc ( cmd, &in, &out );
+    if ( ret == PLUGIN_CMD_SUCCESS ) {
+        strncpy ( out_buf, out.array_of_parameter[0].v_string.data, out_len - 1 );
+        out_buf[out_len - 1] = '\0';
+        success = 1;
+        release_parameters ( &out );
+    }
+
+    release_parameters ( &in );
+    return success;
+}
+
 // return 1 if locked
 // return 0 if unlocked
 // return -1 if request failed
index 47ed3dc..1b2ccbe 100644 (file)
 
 #include "sdbd_plugin.h"
 
-#define PLUGIN_PATH    "/usr/lib/libsdbd_plugin.so"
+#define PLUGIN_PATH        "/usr/lib/libsdbd_plugin.so"
+#define PLUGIN_XML_PATH    "/etc/sdbd/commands.xml"
+
+extern char* extcmd;
 
 int default_plugin_init ( eventfunc event_cb, registerfunc register_func );
 int default_plugin_sync_proc ( int cmd, parameters* in, parameters* out );
index 38a6b21..8b79e84 100644 (file)
--- a/src/sdb.c
+++ b/src/sdb.c
@@ -628,8 +628,13 @@ static void send_connect(atransport *t)
         snprintf((char*) cp->data, sizeof cp->data, "%s::%s::%d", sdb_device_banner, device_name, status);
     }
 
-    D("CNXN data:%s\n", (char*)cp->data);
+    if (extcmd != NULL) {
+        char extbuf[4096];
+        snprintf(extbuf, sizeof extbuf, "::%s", extcmd);
+        strcat((char*) cp->data, extbuf);
+    }
     cp->msg.data_length = strlen((char*) cp->data) + 1;
+    D("CNXN data: %s\n", (char*)cp->data);
 
     send_packet(cp, t);
 }
index 7f61a0b..b6863b0 100644 (file)
@@ -910,6 +910,191 @@ static int create_syncproc_thread()
     return ret_fd;
 }
 
+static int create_extcmd_subproc_thread(const char *name, int lines, int columns)
+{
+    stinfo *sti;
+    sdb_thread_t t;
+    int ret_fd;
+    pid_t pid;
+    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));
+
+    envp[envp_cnt++] = strdup("TERM=linux");
+    envp[envp_cnt++] = strdup("DISPLAY=:0");
+
+    if (should_drop_privileges()) {
+        if (g_sdk_home_dir_env) {
+            envp[envp_cnt++] = strdup(g_sdk_home_dir_env);
+        } else {
+            envp[envp_cnt++] = strdup("HOME=/home/owner");
+        }
+        get_env("ENV_PATH", &value);
+    } else {
+        get_env("ENV_SUPATH", &value);
+        if(value == NULL) {
+            get_env("ENV_ROOTPATH", &value);
+        }
+        envp[envp_cnt++] = strdup("HOME=/root");
+    }
+    if (value != NULL) {
+        trim_value = str_trim(value);
+        if (trim_value != NULL) {
+            // if string is not including 'PATH=', append it.
+            if (strncmp(trim_value, "PATH", 4)) {
+                snprintf(path, sizeof(path), "PATH=%s", trim_value);
+            } else {
+                snprintf(path, sizeof(path), "%s", trim_value);
+            }
+            envp[envp_cnt++] = strdup(path);
+        } else {
+            snprintf(path, sizeof(path), "%s", value);
+            envp[envp_cnt++] = strdup(path);
+        }
+        free(value);
+    }
+
+    /* get environment variables from plugin */
+    char *envp_plugin = NULL;
+    envp_plugin = malloc(ENV_BUF_MAX);
+    if (envp_plugin == NULL) {
+        E("Cannot allocate the shell commnad buffer.");
+        return -1;
+    }
+    memset(envp_plugin, 0, ENV_BUF_MAX);
+    if (!request_extcmd_conversion_to_plugin(PLUGIN_SYNC_CMD_GET_SHELL_ENV, NULL,
+                envp_plugin, ENV_BUF_MAX)) {
+        E("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_extcmd_validity_to_plugin(PLUGIN_SYNC_CMD_VERIFY_SHELLCMD, name)) {
+            E("This extcmd command is invalid. (%s)\n", name);
+            return -1;
+        }
+
+        // Convert the shell command.
+        char *new_cmd = NULL;
+        new_cmd = malloc(SDBD_SHELL_CMD_MAX);
+        if(new_cmd == NULL) {
+            E("Cannot allocate the shell commnad buffer.");
+            return -1;
+        }
+
+        memset(new_cmd, 0, SDBD_SHELL_CMD_MAX);
+        if(!request_extcmd_conversion_to_plugin(PLUGIN_SYNC_CMD_CONVERT_SHELLCMD, name, new_cmd, SDBD_SHELL_CMD_MAX)) {
+            E("Failed to convert the shell command. (%s)\n", name);
+            free(new_cmd);
+            return -1;
+        }
+
+        D("converted cmd : %s\n", new_cmd);
+
+        char *args[] = {
+            USER_DAEMON_COMMAND,
+            "-c",
+            NULL,
+            NULL,
+        };
+        args[2] = new_cmd;
+
+        ret_fd = create_userprocess(USER_DAEMON_COMMAND, &pid, (char * const*)args, (char * const*)envp);
+        free(new_cmd);
+    } else { // in case of shell interactively
+        // Check the capability for interactive shell support.
+        if (!is_support_interactive_shell()) {
+            E("This platform dose NOT support the interactive shell\n");
+            return -1;
+        }
+
+        char * const args[] = {
+                USER_DAEMON_COMMAND,
+                "-",
+                NULL,
+        };
+        ret_fd = create_userprocess(USER_DAEMON_COMMAND, &pid, (char * const*)args, (char * const*)envp);
+#if 0   // FIXME: should call login command instead of /bin/sh
+        if (should_drop_privileges()) {
+            char *args[] = {
+                USER_DAEMON_COMMAND,
+                "-",
+                NULL,
+            };
+            ret_fd = create_userprocess(USER_DAEMON_COMMAND, &pid, args, envp);
+        } else {
+            char *args[] = {
+                LOGIN_COMMAND,
+                "-f",
+                SUPER_USER,
+                NULL,
+            };
+            ret_fd = create_subprocess(LOGIN_COMMAND, &pid, args, envp);
+        }
+#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) {
+        E("cannot create service thread\n");
+        return -1;
+    }
+
+    if (lines > 0 && columns > 0) {
+        D("shell size lines=%d, columns=%d\n", lines, columns);
+        struct winsize win_sz;
+        win_sz.ws_row = lines;
+        win_sz.ws_col = columns;
+
+        if (ioctl(ret_fd, TIOCSWINSZ, &win_sz) < 0) {
+            E("failed to sync window size.\n");
+        }
+    }
+
+    sti = malloc(sizeof(stinfo));
+    if(sti == 0) fatal("cannot allocate stinfo");
+    sti->func = subproc_waiter_service;
+    sti->cookie = (void*)((intptr_t)pid);
+    sti->fd = ret_fd;
+
+    if(sdb_thread_create( &t, service_bootstrap_func, sti)){
+        free(sti);
+        sdb_close(ret_fd);
+        E("cannot create service thread\n");
+        return -1;
+    }
+
+    D("service thread started, fd=%d pid=%d\n",ret_fd, pid);
+    return ret_fd;
+}
+
 static void get_platforminfo(int fd, void *cookie) {
     pinfo sysinfo;
 
@@ -1213,6 +1398,65 @@ void handle_grantfile(int fd, void *cookie) {
     sdb_close(fd);
 }
 
+int request_extcmd_to_plugin(const char* in_buf) {
+    char full_cmd[ENV_BUF_MAX] = {0,};
+    char *tokens[MAX_TOKENS];
+    int args_cnt = tokenize(in_buf, ":", tokens, MAX_TOKENS);
+    if (args_cnt < 3) {
+        E("failed to parse extcmd.\n");
+        return 0;
+    }
+
+    char* cmd_name = tokens[0];
+    char* cmd_no = tokens[args_cnt - 2];
+    int cmd = atoi(cmd_no);
+    char* exec_type = tokens[args_cnt - 1];
+
+    strcat(full_cmd, cmd_name);
+    int i = 1;
+    for(;i < args_cnt - 2;i++) {
+        strcat(full_cmd, " ");
+        strcat(full_cmd, tokens[i]);
+    }
+    D("full extcmd: %s\n", full_cmd);
+    if (!strcmp(exec_type, "sync")) {
+        return create_extcmd_subproc_thread(full_cmd, 0, 0);
+    }
+
+    else if (!strcmp(exec_type, "async")) {
+        parameters* in;
+        int fd;
+
+        in = (parameters*) malloc(sizeof(parameters));
+        if (in == NULL) {
+            E("failed to allocate memory for the parameters\n");
+            return -1;
+        }
+
+        if (full_cmd != NULL) {
+            in->number_of_parameter = 1;
+            in->array_of_parameter = (parameter*) malloc(sizeof(parameter));
+            if (in->array_of_parameter == NULL) {
+                free(in);
+                E("failed to allocate memory for the parameter\n");
+                return -1;
+            }
+            in->array_of_parameter[0].type = type_string;
+            in->array_of_parameter[0].v_string.length = strlen(full_cmd);
+            in->array_of_parameter[0].v_string.data = strdup(full_cmd);
+        } else {
+            in->number_of_parameter = 0;
+            in->array_of_parameter = NULL;
+        }
+
+        fd = create_async_extcmd_proc_thread(cmd, in);
+
+        return fd;
+    }
+
+    return 0;
+}
+
 int service_to_fd(const char *name)
 {
     int ret = -1;
@@ -1325,6 +1569,8 @@ int service_to_fd(const char *name)
         ret = create_service_thread(handle_grantfile, (void*)name+10);
     } else if(!strncmp(name, "appcmd:", 7)){
         ret = request_appcmd_to_plugin(name+7);
+    } else if(!strncmp(name, "extcmd:", 7)) {
+        ret = request_extcmd_to_plugin(name+7);
     }
 
     if (ret >= 0) {