version up to 2.1.0 submit/tizen_2.1/20130403.165033
authoryoonki.park <yoonki.park@samsung.com>
Wed, 3 Apr 2013 16:48:06 +0000 (01:48 +0900)
committeryoonki.park <yoonki.park@samsung.com>
Wed, 3 Apr 2013 16:48:06 +0000 (01:48 +0900)
add root command
add drop privilege to developer
listen on port 26101
add to fork process when pulling/pushing file in developer mode

Change-Id: I35d96efe08dfbcf7b3d35725f39f92729bae2efa
Signed-off-by: Yoonki Park <yoonki.park@samsung.com>
21 files changed:
Makefile
packaging/sdbd.spec
src/commandline.c
src/file_sync_client.c
src/file_sync_service.c
src/file_sync_service.h
src/fileutils.c [new file with mode: 0644]
src/fileutils.h [new file with mode: 0644]
src/init.c [new file with mode: 0644]
src/libsmack.c [new file with mode: 0644]
src/properties.c
src/sdb.c
src/sdb.h
src/sdktools.c [new file with mode: 0644]
src/sdktools.h [new file with mode: 0644]
src/services.c
src/smack.h [new file with mode: 0644]
src/strutils.c [new file with mode: 0644]
src/strutils.h [new file with mode: 0644]
src/sysdeps.h
src/usb_linux.c

index 60389b8d2fab53e33827946df06c6b9fdad42428..0286362dddc92f626002e520430fd3366d0da1c7 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -82,11 +82,16 @@ SDBD_SRC_FILES := \
        src/socket_loopback_server.c \
        src/socket_network_client.c \
        src/properties.c \
-       src/android_reboot.c
+       src/android_reboot.c \
+       src/sdktools.c \
+       src/strutils.c \
+       src/libsmack.c \
+       src/init.c \
+       src/fileutils.c
 
 SDBD_CFLAGS := -O2 -g -DSDB_HOST=0 -Wall -Wno-unused-parameter
 SDBD_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE
-SDBD_CFLAGS += -DHAVE_FORKEXEC -fPIE
+SDBD_CFLAGS += -DHAVE_FORKEXEC -fPIE -D_DROP_PRIVILEGE
 
 IFLAGS := -Iinclude -Isrc
 OBJDIR := bin
@@ -132,8 +137,10 @@ ifeq ($(MODULE),sdbd)
        mkdir -p $(DESTDIR)/$(INITSCRIPTDIR)
        install script/sdbd $(DESTDIR)/$(INITSCRIPTDIR)/sdbd
 endif
+ifeq ($(TARGET_ARCH),x86)
        mkdir -p $(DESTDIR)/$(RCSCRIPTDIR)
        install script/S06sdbd $(DESTDIR)/$(RCSCRIPTDIR)/S06sdbd
+endif
 
 clean :
        rm -rf $(OBJDIR)/*
index 2ba0402f2557dc19dd8c114e3fbefef7e93eab35..81b1de443ecce08bb931e21e3a718f041b9680b7 100644 (file)
@@ -1,7 +1,7 @@
 Name:       sdbd
 Summary:    SDB daemon
-Version:    2.0.2
-Release:    2
+Version:    2.1.0
+Release:    0
 Group:      TO_BE/FILLED_IN
 License:    TO BE FILLED IN
 Source0:    %{name}-%{version}.tar.gz
@@ -26,7 +26,10 @@ rm -rf %{buildroot}
 %defattr(-,root,root,-) 
 %{_prefix}/sbin/sdbd
 %{_sysconfdir}/init.d/sdbd
-%{_sysconfdir}/rc.d/rc3.d
+
+%ifarch %{ix86}
+    %{_sysconfdir}/rc.d/rc3.d
+%endif
 
 %changelog
 * Mon Dec 02 2012 Yoonki Park <yoonki.park@samsung.com>
index 9c2885a13008ee6ad04fa81331b7a20a065ef6bf..730509be5688ec91d77b3b0d9c2abb1ca62514e4 100644 (file)
@@ -47,6 +47,7 @@ int uninstall_app_sdb(const char *app_id);
 int install_app_sdb(const char *srcpath);
 int uninstall_app(transport_type transport, char* serial, int argc, char** argv);
 int sdb_command2(const char* cmd);
+void version_sdbd(transport_type ttype, char* serial);
 
 static const char *gProductOutPath = NULL;
 
@@ -86,11 +87,11 @@ void help()
     " Usage : sdb [option] <command> [parameters]\n"
         "\n"
     " options:\n"
-    " -d                            - directs command to the only connected USB device\n"
-    "                                 returns an error if more than one USB device is present.\n"
-    " -e                            - directs command to the only running emulator.\n"
-    "                                 returns an error if more than one emulator is running.\n"
-    " -s <serial number>            - directs command to the USB device or emulator with\n"
+    " -d                            - direct command to the only connected USB device\n"
+    "                                 return an error if more than one USB device is present.\n"
+    " -e                            - direct command to the only running emulator.\n"
+    "                                 return an error if more than one emulator is running.\n"
+    " -s <serial number>            - direct command to the USB device or emulator with\n"
     "                                 the given serial number.\n"
     " devices                       - list all connected devices\n"
     " connect <host>[:<port>]       - connect to a device via TCP/IP\n"
@@ -101,14 +102,14 @@ void help()
     "                                 will disconnect from all connected TCP/IP devices.\n"
     "\n"
     " commands:\n"
-    "  sdb push <local> <remote> [-with-utf8]\n"
+    "  sdb push <local> <remote> [--with-utf8]\n"
     "                               - copy file/dir to device\n"
-    "                                 (-with-utf8 means to create the remote file with utf8 character encoding)\n"
+    "                                 (--with-utf8 means to create the remote file with utf-8 character encoding)\n"
     "  sdb pull <remote> [<local>]  - copy file/dir from device\n"
     "  sdb shell                    - run remote shell interactively\n"
     "  sdb shell <command>          - run remote shell \n"
-    "  sdb dlog [ <filter-spec> ]   - view device log\n"
-    "  sdb install <path_to_tpk>    - push tpk package file and install it\n"
+    "  sdb dlog [<filter-spec>]     - view device log\n"
+    "  sdb install <path-to-tpk>    - push tpk package file and install it\n"
     "  sdb uninstall <appid>        - uninstall this app from the device\n"
     "  sdb forward <local> <remote> - forward socket connections\n"
 
@@ -119,12 +120,13 @@ void help()
     "\n"
     "  sdb start-server             - ensure that there is a server running\n"
     "  sdb kill-server              - kill the server if it is running\n"
-    "  sdb get-state                - prints: offline | bootloader | device\n"
-    "  sdb get-serialno             - prints: <serial-number>\n"
+    "  sdb get-state                - print: offline | bootloader | device\n"
+    "  sdb get-serialno             - print: <serial-number>\n"
     "  sdb status-window            - continuously print device status for a specified device\n"
-    "  sdb usb                      - restarts the sdbd daemon listing on USB\n"
-//    "  sdb tcpip <port>             - restarts the sdbd daemon listing on TCP on the specified port"
-    "  sdb tcpip                    - restarts the sdbd daemon listing on TCP"
+//    "  sdb usb                      - restarts the sdbd daemon listing on USB\n"
+//    "  sdb tcpip                    - restarts the sdbd daemon listing on TCP\n"
+    "  sdb root <on|off>            - switch to root or developer account mode\n"
+    "                                 'on' means to root mode, and vice versa"
     "\n"
         );
 }
@@ -567,21 +569,14 @@ static int logcat(transport_type transport, char* serial, int argc, char **argv)
 {
     char buf[4096];
 
-    char *log_tags;
-    char *quoted_log_tags;
-
-    log_tags = getenv("ANDROID_LOG_TAGS");
-    quoted_log_tags = dupAndQuote(log_tags == NULL ? "" : log_tags);
-
     snprintf(buf, sizeof(buf),
-        "shell:export ANDROID_LOG_TAGS=\"\%s\" ; exec logcat",
-        quoted_log_tags);
-
-    free(quoted_log_tags);
+        "shell:/usr/bin/dlogutil");
 
+/*
     if (!strcmp(argv[0],"longcat")) {
         strncat(buf, " -v long", sizeof(buf)-1);
     }
+*/
 
     argc -= 1;
     argv += 1;
@@ -931,8 +926,9 @@ int sdb_commandline(int argc, char **argv)
         argv++;
     }
 
-    sdb_set_transport(ttype, serial);
-    sdb_set_tcp_specifics(server_port);
+
+//    sdb_set_transport(ttype, serial);
+//    sdb_set_tcp_specifics(server_port);
 
     if (is_server) {
         if (no_daemon || is_daemon) {
@@ -951,6 +947,23 @@ top:
         return usage();
     }
 
+    // first, get the uniq device from the partial serial with prefix matching
+    if (serial) {
+        char *tmp;
+        snprintf(buf, sizeof(buf), "host:serial-match:%s", serial);
+        tmp = sdb_query(buf);
+        if (tmp) {
+            //printf("connect to device: %s\n", tmp);
+            serial = strdup(tmp);
+            sdb_set_transport(ttype, serial);
+            sdb_set_tcp_specifics(server_port);
+        } else {
+            return 1;
+        }
+    } else {
+        sdb_set_transport(ttype, serial);
+        sdb_set_tcp_specifics(server_port);
+    }
     /* sdb_connect() commands */
 
     if(!strcmp(argv[0], "devices")) {
@@ -1181,7 +1194,7 @@ top:
 
         if(argc < 3) return usage();
         if (argv[argc-1][0] == '-') {
-            if (!strcmp(argv[argc-1], "-with-utf8")) {
+            if (!strcmp(argv[argc-1], "--with-utf8")) {
                 utf8 = 1;
                 argc = argc - 1;
             } else {
@@ -1284,7 +1297,7 @@ top:
         return 0;
     }
 
-    if(!strcmp(argv[0],"logcat") || !strcmp(argv[0],"lolcat") || !strcmp(argv[0],"longcat")) {
+    if(!strcmp(argv[0],"dlog")) {
         return logcat(ttype, serial, argc, argv);
     }
 
@@ -1323,7 +1336,11 @@ top:
     }
 
     if(!strcmp(argv[0], "version")) {
-        version(stdout);
+        if (ttype == kTransportUsb || ttype == kTransportLocal) {
+            version_sdbd(ttype, serial);
+        } else {
+            version(stdout);
+        }
         return 0;
     }
 
@@ -1350,7 +1367,9 @@ static int do_cmd(transport_type ttype, char* serial, char *cmd, ...)
     }
 
     argv[argc++] = cmd;
-    while((argv[argc] = va_arg(ap, char*)) != 0) argc++;
+    while((argv[argc] = va_arg(ap, char*)) != 0) {
+        argc++;
+    }
     va_end(ap);
 
 #if 0
@@ -1486,8 +1505,16 @@ int install_app_sdb(const char *srcpath) {
 int uninstall_app_sdb(const char *appid) {
     const char* SHELL_UNINSTALL_CMD ="shell:pkgcmd -u -t tpk -n %s -q";
     char full_cmd[PATH_MAX];
+    int result = 0;
     snprintf(full_cmd, sizeof full_cmd, SHELL_UNINSTALL_CMD, appid);
-    return sdb_command(full_cmd);
+    result = sdb_command2(full_cmd);
+
+    if(result < 0) {
+        fprintf(stderr, "error: %s\n", sdb_error());
+        return result;
+    }
+
+    return 0;
 }
 
 int uninstall_app(transport_type transport, char* serial, int argc, char** argv)
@@ -1644,3 +1671,8 @@ cleanup_apk:
 
     return err;
 }
+
+void version_sdbd(transport_type ttype, char* serial) {
+    char* VERSION_QUERY ="shell:rpm -qa | grep sdbd";
+    send_shellcommand(ttype, serial, VERSION_QUERY);
+}
index 95e8632cc1596f2e62d8dda0949e2b0d4bb5cc25..8561250b19dc42e86e4d620649e3223c84af8ae2 100644 (file)
@@ -978,7 +978,8 @@ int do_sync_pull(const char *rpath, const char *lpath)
         return 1;
     }
     if(mode == 0) {
-        fprintf(stderr,"remote object '%s' does not exist\n", rpath);
+        fprintf(stderr,"'%s': No such file or directory\n", rpath);
+        sync_quit(fd);
         return 1;
     }
 
@@ -1019,7 +1020,7 @@ int do_sync_pull(const char *rpath, const char *lpath)
             return 0;
         }
     } else {
-        fprintf(stderr,"remote object '%s' not a file or directory\n", rpath);
+        fprintf(stderr,"'%s': No such file or directory\n", rpath);
         return 1;
     }
 }
index 75f2840adb152448ac559ce2bb314f0a65436372..7437e9bd4a79a02b5baba76215eb6e4b4e936ed0 100644 (file)
@@ -22,7 +22,7 @@
 #include <sys/types.h>
 #include <dirent.h>
 #include <utime.h>
-
+#include <regex.h>
 #include <errno.h>
 
 #include "sysdeps.h"
 #include "sdb.h"
 #include "file_sync_service.h"
 
+struct sync_permit_rule
+{
+    const char *name;
+    const char *regx;
+    int mode; // 0:push, 1: pull, 2: push&push
+};
+
+struct sync_permit_rule sdk_sync_permit_rule[] = {
+//    /* 0 */ {"rds", "^((/opt/apps)|(/opt/usr/apps))/[a-zA-Z0-9]{10}/info/\\.sdk_delta\\.info$", 1},
+    /* 1 */ {"unitest", "^((/opt/apps)|(/opt/usr/apps))/[a-zA-Z0-9]{10}/data/[a-zA-Z0-9_\\-]{1,50}\\.xml$", 1},
+    /* 2 */ {"codecoverage", "^((/opt/apps)|(/opt/usr/apps))/[a-zA-Z0-9]{10}/data/+([a-zA-Z0-9_/])*+[a-zA-Z0-9_\\-]{1,50}\\.gcda$", 1},
+    /* end */ {NULL, NULL, 0}
+};
+
 /* The typical default value for the umask is S_IWGRP | S_IWOTH (octal 022).
  * Before use the DIR_PERMISSION, the process umask value should be set 0 using umask().
  */
@@ -72,6 +86,7 @@ static int do_stat(int s, const char *path)
         msg.stat.mode = 0;
         msg.stat.size = 0;
         msg.stat.time = 0;
+        D("failed to stat %s due to: %s\n", path, strerror(errno));
     } else {
         msg.stat.mode = htoll(st.st_mode);
         msg.stat.size = htoll(st.st_size);
@@ -100,7 +115,8 @@ static int do_list(int s, const char *path)
     msg.dent.id = ID_DENT;
 
     d = opendir(path);
-    if(d == 0) {
+    if(d == NULL) {
+        D("failed to open dir due to: %s\n", strerror(errno));
         goto done;
     }
 
@@ -180,13 +196,11 @@ static int handle_send_file(int s, char *path, mode_t mode, char *buffer)
             return -1;
         fd = -1;
     }
-
     for(;;) {
         unsigned int len;
 
         if(readx(s, &msg.data, sizeof(msg.data)))
             goto fail;
-
         if(msg.data.id != ID_DATA) {
             if(msg.data.id == ID_DONE) {
                 timestamp = ltohl(msg.data.size);
@@ -228,6 +242,9 @@ static int handle_send_file(int s, char *path, mode_t mode, char *buffer)
             return -1;
         // flush file system buffers due to N_SE-22305
         sync();
+    } else {
+        D("sync error: %d!!!\n", fd);
+        return -1;
     }
     return 0;
 
@@ -330,7 +347,6 @@ static int do_send(int s, char *path, char *buffer)
 
         //mode |= ((mode >> 3) & 0070);
         //mode |= ((mode >> 3) & 0007);
-
         ret = handle_send_file(s, path, mode, buffer);
     }
 
@@ -373,10 +389,55 @@ static int do_recv(int s, const char *path, char *buffer)
     if(writex(s, &msg.data, sizeof(msg.data))) {
         return -1;
     }
+    return 0;
+}
+
+static int verify_sync_rule(const char* path) {
+    regex_t regex;
+    int ret;
+    char buf[PATH_MAX];
+    int i=0;
 
+    for (i=0; sdk_sync_permit_rule[i].regx != NULL; i++) {
+        ret = regcomp(&regex, sdk_sync_permit_rule[i].regx, REG_EXTENDED);
+        if(ret){
+            return 0;
+        }
+        // execute regular expression
+        ret = regexec(&regex, path, 0, NULL, 0);
+        if(!ret){
+            regfree(&regex);
+            D("found matched rule(%s) from %s path\n", sdk_sync_permit_rule[i].name, path);
+            return 1;
+        } else if( ret == REG_NOMATCH ){
+            // do nothin
+        } else{
+            regerror(ret, &regex, buf, sizeof(buf));
+            D("regex match failed(%s): %s\n",sdk_sync_permit_rule[i].name, buf);
+        }
+    }
+    regfree(&regex);
     return 0;
 }
 
+void file_sync_subproc(int fd, void *cookie) {
+    if (should_drop_privileges()) {
+        pid_t pid = fork();
+        int ret = 0;
+        if (pid == 0) {
+            file_sync_service(fd, cookie);
+        } else if (pid > 0) {
+            waitpid(pid, &ret, 0);
+        }
+        if(pid < 0) {
+            D("- fork failed: %s -\n", strerror(errno));
+            return;
+        }
+    } else {
+        file_sync_service(fd, cookie);
+    }
+}
+
 void file_sync_service(int fd, void *cookie)
 {
     syncmsg msg;
@@ -407,6 +468,9 @@ void file_sync_service(int fd, void *cookie)
         msg.req.namelen = 0;
         D("sync: '%s' '%s'\n", (char*) &msg.req, name);
 
+        if (should_drop_privileges() && !verify_sync_rule(name)) {
+            set_developer_privileges();
+        }
         switch(msg.req.id) {
         case ID_STAT:
             if(do_stat(fd, name)) goto fail;
index 84f06bb4f86bd1d650fb65bd5d01b69319bd44e5..68059da67866510dad4c2a1075ccf65b0a1965be 100644 (file)
@@ -77,6 +77,7 @@ typedef union {
 
 
 void file_sync_service(int fd, void *cookie);
+void file_sync_subproc(int fd, void *cookie);
 int do_sync_ls(const char *path);
 int do_sync_push(const char *lpath, const char *rpath, int verifyApk, int isUtf8);
 int do_sync_sync(const char *lpath, const char *rpath, int listonly);
diff --git a/src/fileutils.c b/src/fileutils.c
new file mode 100644 (file)
index 0000000..bb5071b
--- /dev/null
@@ -0,0 +1,49 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <limits.h>
+
+static int recurse(const char *path, mode_t mode, int (*fn)(const char *,mode_t, int)) {
+    struct stat st;
+    char dir[PATH_MAX];
+
+    if (path == NULL) {
+        return -1;
+    }
+    if (lstat (path, &st) == -1) {
+        return -1;
+    }
+    if (strrchr(path, '/') != NULL) {
+        int n = strlen(path)-strlen(strrchr(path, '/'));
+        if (n >= PATH_MAX) {
+            return -1;
+        }
+        strncpy(dir, path, n);
+        dir[n] = '\0';
+        fn(dir, mode,1);
+        return 1;
+    }
+    return -1;
+}
+
+int sdb_chmod(const char *path, mode_t mode, int recursive) {
+#ifdef HAVE_WIN32_PROC
+    fprintf(stderr, "error: sdb_chmod not implemented on Win32 (%s)\n", path);
+    return -1;
+#else
+    struct stat st;
+
+    if (stat (path, &st) == -1)
+        return -1;
+
+    if (chmod (path, mode) == -1) {
+        return -1;
+    }
+    if (recursive) {
+        return recurse(path, mode, sdb_chmod);
+    }
+    return 1;
+#endif
+}
diff --git a/src/fileutils.h b/src/fileutils.h
new file mode 100644 (file)
index 0000000..4debc92
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef _FILEUTILS_H_
+#define _FILEUTILS_H_
+
+int sdb_chmod(const char *path, mode_t mode, int recursive);
+#endif
+
diff --git a/src/init.c b/src/init.c
new file mode 100644 (file)
index 0000000..bec59f2
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * This file is part of libsmack. Derived from libselinux/src/init.c.
+ *
+ * Copyright (C) 2012 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * Authors:
+ * Passion Zhao <passion.zhao@intel.com>
+ */
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdio_ext.h>
+#include <dlfcn.h>
+#include <sys/statvfs.h>
+#include <sys/vfs.h>
+#include <stdint.h>
+#include <limits.h>
+
+/*
+ *  * smackfs magic number
+ *   */
+#define SMACK_MAGIC     0x43415d53 /* "SMAC" */
+
+/* smack file system type */
+#define SMACKFS "smackfs"
+
+#define SMACKFSMNT "/sys/fs/smackfs/"
+#define OLDSMACKFSMNT "/smack"
+
+char *smack_mnt = NULL;
+
+void set_smackmnt(const char *mnt)
+{
+       smack_mnt = strdup(mnt);
+}
+
+/* Verify the mount point for smack file system has a smackfs.
+ * If the file system:
+ * Exist,
+ * Is mounted with an smack file system,
+ * The file system is read/write
+ * then set this as the default file system.
+ */
+static int verify_smackmnt(const char *mnt)
+{
+       struct statfs sfbuf;
+       int rc;
+
+       do {
+               rc = statfs(mnt, &sfbuf);
+       } while (rc < 0 && errno == EINTR);
+
+       if (rc == 0) {
+               if ((uint32_t)sfbuf.f_type == (uint32_t)SMACK_MAGIC) {
+                       struct statvfs vfsbuf;
+                       rc = statvfs(mnt, &vfsbuf);
+                       if (rc == 0) {
+                               if (!(vfsbuf.f_flag & ST_RDONLY)) {
+                                       set_smackmnt(mnt);
+                               }
+                               return 0;
+                       }
+               }
+       }
+
+       return -1;
+}
+
+int smackfs_exists(void)
+{
+       int exists = 0;
+       FILE *fp = NULL;
+       char *buf = NULL;
+       size_t len;
+       ssize_t num;
+
+       fp = fopen("/proc/filesystems", "r");
+       if (!fp)
+               return 1; /* Fail as if it exists */
+
+       __fsetlocking(fp, FSETLOCKING_BYCALLER);
+
+       num = getline(&buf, &len, fp);
+       while (num != -1) {
+               if (strstr(buf, SMACKFS)) {
+                       exists = 1;
+                       break;
+               }
+               num = getline(&buf, &len, fp);
+       }
+
+       free(buf);
+       fclose(fp);
+       return exists;
+}
+
+static void init_smackmnt(void)
+{
+       char *buf=NULL, *p;
+       FILE *fp=NULL;
+       size_t len;
+       ssize_t num;
+
+       if (smack_mnt)
+               return;
+
+       if (verify_smackmnt(SMACKFSMNT) == 0) 
+               return;
+
+       if (verify_smackmnt(OLDSMACKFSMNT) == 0) 
+               return;
+
+       /* Drop back to detecting it the long way. */
+       if (!smackfs_exists())
+               goto out;
+
+       /* At this point, the usual spot doesn't have an smackfs so
+        * we look around for it */
+       fp = fopen("/proc/mounts", "r");
+       if (!fp)
+               goto out;
+
+       __fsetlocking(fp, FSETLOCKING_BYCALLER);
+       while ((num = getline(&buf, &len, fp)) != -1) {
+               char *tmp;
+               p = strchr(buf, ' ');
+               if (!p)
+                       goto out;
+               p++;
+
+               tmp = strchr(p, ' ');
+               if (!tmp)
+                       goto out;
+
+               if (!strncmp(tmp + 1, SMACKFS" ", strlen(SMACKFS)+1)) {
+                       *tmp = '\0';
+                       break;
+               }
+       }
+
+       /* If we found something, dup it */
+       if (num > 0)
+               verify_smackmnt(p);
+
+      out:
+       free(buf);
+       if (fp)
+               fclose(fp);
+       return;
+}
+
+void fini_smackmnt(void)
+{
+       free(smack_mnt);
+       smack_mnt = NULL;
+}
+
+static void init_lib(void) __attribute__ ((constructor));
+static void init_lib(void)
+{
+       init_smackmnt();
+}
+
+static void fini_lib(void) __attribute__ ((destructor));
+static void fini_lib(void)
+{
+       fini_smackmnt();
+}
diff --git a/src/libsmack.c b/src/libsmack.c
new file mode 100644 (file)
index 0000000..03fa8eb
--- /dev/null
@@ -0,0 +1,811 @@
+/*
+ * This file is part of libsmack
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2011 Intel Corporation
+ * Copyright (C) 2012 Samsung Electronics Co.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * Authors:
+ * Jarkko Sakkinen <jarkko.sakkinen@intel.com>
+ * Brian McGillion <brian.mcgillion@intel.com>
+ * Passion Zhao <passion.zhao@intel.com>
+ * Rafal Krypa <r.krypa@samsung.com>
+ */
+
+#include "smack.h"
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/xattr.h>
+#include <unistd.h>
+#include <limits.h>
+
+#define ACC_LEN 5
+#define LOAD_LEN (2 * (SMACK_LABEL_LEN + 1) + 2 * ACC_LEN + 1)
+
+#define LEVEL_MAX 255
+#define NUM_LEN 4
+#define BUF_SIZE 512
+#define CAT_MAX_COUNT 240
+#define CAT_MAX_VALUE 63
+#define CIPSO_POS(i)   (SMACK_LABEL_LEN + 1 + NUM_LEN + NUM_LEN + i * NUM_LEN)
+#define CIPSO_MAX_SIZE CIPSO_POS(CAT_MAX_COUNT)
+#define CIPSO_NUM_LEN_STR "%-4d"
+
+#define KERNEL_LONG_FORMAT "%s %s %s"
+#define KERNEL_SHORT_FORMAT "%-23s %-23s %5s"
+#define KERNEL_MODIFY_FORMAT "%s %s %s %s"
+#define READ_BUF_SIZE LOAD_LEN + 1
+#define SELF_LABEL_FILE "/proc/self/attr/current"
+
+extern char *smack_mnt;
+
+typedef int (*getxattr_func)(void*, const char*, void*, size_t);
+typedef int (*setxattr_func)(const void*, const char*, const void*, size_t, int);
+typedef int (*removexattr_func)(void*, const char*);
+
+struct smack_rule {
+       char subject[SMACK_LABEL_LEN + 1];
+       char object[SMACK_LABEL_LEN + 1];
+       int is_modify;
+       char access_set[ACC_LEN + 1];
+       char access_add[ACC_LEN + 1];
+       char access_del[ACC_LEN + 1];
+       struct smack_rule *next;
+};
+
+struct smack_accesses {
+       struct smack_rule *first;
+       struct smack_rule *last;
+};
+
+struct cipso_mapping {
+       char label[SMACK_LABEL_LEN + 1];
+       int cats[CAT_MAX_VALUE];
+       int ncats;
+       int level;
+       struct cipso_mapping *next;
+};
+
+struct smack_cipso {
+       struct cipso_mapping *first;
+       struct cipso_mapping *last;
+};
+
+static int accesses_apply(struct smack_accesses *handle, int clear);
+static inline void parse_access_type(const char *in, char out[ACC_LEN + 1]);
+static inline char* get_xattr_name(enum smack_label_type type);
+
+int smack_accesses_new(struct smack_accesses **accesses)
+{
+       struct smack_accesses *result;
+
+       result = calloc(sizeof(struct smack_accesses), 1);
+       if (result == NULL)
+               return -1;
+
+       *accesses = result;
+       return 0;
+}
+
+void smack_accesses_free(struct smack_accesses *handle)
+{
+       if (handle == NULL)
+               return;
+
+       struct smack_rule *rule = handle->first;
+       struct smack_rule *next_rule = NULL;
+
+       while (rule != NULL) {
+               next_rule = rule->next;
+               free(rule);
+               rule = next_rule;
+       }
+
+       free(handle);
+}
+
+int smack_accesses_save(struct smack_accesses *handle, int fd)
+{
+       struct smack_rule *rule = handle->first;
+       FILE *file;
+       int ret;
+       int newfd;
+
+       newfd = dup(fd);
+       if (newfd == -1)
+               return -1;
+
+       file = fdopen(newfd, "w");
+       if (file == NULL) {
+               close(newfd);
+               return -1;
+       }
+
+       while (rule) {
+               if (rule->is_modify) {
+                       ret = fprintf(file, "%s %s %s %s\n",
+                                     rule->subject, rule->object,
+                                     rule->access_add, rule->access_del);
+               } else {
+                       ret = fprintf(file, "%s %s %s\n",
+                                     rule->subject, rule->object,
+                                     rule->access_set);
+               }
+
+               if (ret < 0) {
+                       fclose(file);
+                       return -1;
+               }
+
+               rule = rule->next;
+       }
+
+       fclose(file);
+       return 0;
+}
+
+int smack_accesses_apply(struct smack_accesses *handle)
+{
+       return accesses_apply(handle, 0);
+}
+
+int smack_accesses_clear(struct smack_accesses *handle)
+{
+       return accesses_apply(handle, 1);
+}
+
+int smack_accesses_add(struct smack_accesses *handle, const char *subject,
+                      const char *object, const char *access_type)
+{
+       struct smack_rule *rule = NULL;
+
+       rule = calloc(sizeof(struct smack_rule), 1);
+       if (rule == NULL)
+               return -1;
+
+       strncpy(rule->subject, subject, SMACK_LABEL_LEN + 1);
+       strncpy(rule->object, object, SMACK_LABEL_LEN + 1);
+       parse_access_type(access_type, rule->access_set);
+
+       if (handle->first == NULL) {
+               handle->first = handle->last = rule;
+       } else {
+               handle->last->next = rule;
+               handle->last = rule;
+       }
+
+       return 0;
+}
+
+int smack_accesses_add_modify(struct smack_accesses *handle, const char *subject,
+                      const char *object, const char *access_add, const char *access_del)
+{
+       struct smack_rule *rule = NULL;
+
+       rule = calloc(sizeof(struct smack_rule), 1);
+       if (rule == NULL)
+               return -1;
+
+       strncpy(rule->subject, subject, SMACK_LABEL_LEN + 1);
+       strncpy(rule->object, object, SMACK_LABEL_LEN + 1);
+       parse_access_type(access_add, rule->access_add);
+       parse_access_type(access_del, rule->access_del);
+       rule->is_modify = 1;
+
+       if (handle->first == NULL) {
+               handle->first = handle->last = rule;
+       } else {
+               handle->last->next = rule;
+               handle->last = rule;
+       }
+
+       return 0;
+}
+
+int smack_accesses_add_from_file(struct smack_accesses *accesses, int fd)
+{
+       FILE *file = NULL;
+       char buf[READ_BUF_SIZE];
+       char *ptr;
+       const char *subject, *object, *access, *access2;
+       int newfd;
+       int ret;
+
+       newfd = dup(fd);
+       if (newfd == -1)
+               return -1;
+
+       file = fdopen(newfd, "r");
+       if (file == NULL) {
+               close(newfd);
+               return -1;
+       }
+
+       while (fgets(buf, READ_BUF_SIZE, file) != NULL) {
+               if (strcmp(buf, "\n") == 0)
+                       continue;
+               subject = strtok_r(buf, " \t\n", &ptr);
+               object = strtok_r(NULL, " \t\n", &ptr);
+               access = strtok_r(NULL, " \t\n", &ptr);
+               access2 = strtok_r(NULL, " \t\n", &ptr);
+
+               if (subject == NULL || object == NULL || access == NULL ||
+                   strtok_r(NULL, " \t\n", &ptr) != NULL) {
+                       errno = EINVAL;
+                       fclose(file);
+                       return -1;
+               }
+
+               if (access2 == NULL)
+                       ret = smack_accesses_add(accesses, subject, object, access);
+               else
+                       ret = smack_accesses_add_modify(accesses, subject, object, access, access2);
+
+               if (ret) {
+                       fclose(file);
+                       return -1;
+               }
+       }
+
+       if (ferror(file)) {
+               fclose(file);
+               return -1;
+       }
+
+       fclose(file);
+       return 0;
+}
+
+int smack_have_access(const char *subject, const char *object,
+                     const char *access_type)
+{
+       char buf[LOAD_LEN + 1];
+       char access_type_k[ACC_LEN + 1];
+       int ret;
+       int fd;
+       int access2 = 1;
+       char path[PATH_MAX];
+
+       if (!smack_mnt) {
+               errno = EFAULT;
+               return -1; 
+       }
+       
+       snprintf(path, sizeof path, "%s/access2", smack_mnt);
+       fd = open(path, O_RDWR);
+       if (fd < 0) {
+               if (errno != ENOENT)
+                       return -1;
+               
+               snprintf(path, sizeof path, "%s/access", smack_mnt);
+               fd = open(path, O_RDWR);
+               if (fd < 0)
+                       return -1;
+               access2 = 0;
+       }
+
+       parse_access_type(access_type, access_type_k);
+
+       if (access2)
+               ret = snprintf(buf, LOAD_LEN + 1, KERNEL_LONG_FORMAT,
+                              subject, object, access_type_k);
+       else
+               ret = snprintf(buf, LOAD_LEN + 1, KERNEL_SHORT_FORMAT,
+                              subject, object, access_type_k);
+
+       if (ret < 0) {
+               close(fd);
+               return -1;
+       }
+
+       ret = write(fd, buf, strlen(buf));
+       if (ret < 0) {
+               close(fd);
+               return -1;
+       }
+
+       ret = read(fd, buf, 1);
+       close(fd);
+       if (ret < 0)
+               return -1;
+
+       return buf[0] == '1';
+}
+void smack_cipso_free(struct smack_cipso *cipso)
+{
+       if (cipso == NULL)
+               return;
+
+       struct cipso_mapping *mapping = cipso->first;
+       struct cipso_mapping *next_mapping = NULL;
+
+       while (mapping != NULL) {
+               next_mapping = mapping->next;
+               free(mapping);
+               mapping = next_mapping;
+       }
+}
+
+struct smack_cipso *smack_cipso_new(int fd)
+{
+       struct smack_cipso *cipso = NULL;
+       struct cipso_mapping *mapping = NULL;
+       FILE *file = NULL;
+       char buf[BUF_SIZE];
+       char *label, *level, *cat, *ptr;
+       long int val;
+       int i;
+       int newfd;
+
+       newfd = dup(fd);
+       if (newfd == -1)
+               return NULL;
+
+       file = fdopen(newfd, "r");
+       if (file == NULL) {
+               close(newfd);
+               return NULL;
+       }
+
+       cipso = calloc(sizeof(struct smack_cipso ), 1);
+       if (cipso == NULL) {
+               fclose(file);
+               return NULL;
+       }
+
+       while (fgets(buf, BUF_SIZE, file) != NULL) {
+               mapping = calloc(sizeof(struct cipso_mapping), 1);
+               if (mapping == NULL)
+                       goto err_out;
+
+               label = strtok_r(buf, " \t\n", &ptr);
+               level = strtok_r(NULL, " \t\n", &ptr);
+               cat = strtok_r(NULL, " \t\n", &ptr);
+               if (label == NULL || cat == NULL || level == NULL ||
+                   strlen(label) > SMACK_LABEL_LEN) {
+                       errno = EINVAL;
+                       goto err_out;
+               }
+
+               strcpy(mapping->label, label);
+
+               errno = 0;
+               val = strtol(level, NULL, 10);
+               if (errno)
+                       goto err_out;
+
+               if (val < 0 || val > LEVEL_MAX) {
+                       errno = ERANGE;
+                       goto err_out;
+               }
+
+               mapping->level = val;
+
+               for (i = 0; i < CAT_MAX_COUNT && cat != NULL; i++) {
+                       errno = 0;
+                       val = strtol(cat, NULL, 10);
+                       if (errno)
+                               goto err_out;
+
+                       if (val < 0 || val > CAT_MAX_VALUE) {
+                               errno = ERANGE;
+                               goto err_out;
+                       }
+
+                       mapping->cats[i] = val;
+
+                       cat = strtok_r(NULL, " \t\n", &ptr);
+               }
+
+               mapping->ncats = i;
+
+               if (cipso->first == NULL) {
+                       cipso->first = cipso->last = mapping;
+               } else {
+                       cipso->last->next = mapping;
+                       cipso->last = mapping;
+               }
+       }
+
+       if (ferror(file))
+               goto err_out;
+
+       fclose(file);
+       return cipso;
+err_out:
+       fclose(file);
+       smack_cipso_free(cipso);
+       free(mapping);
+       return NULL;
+}
+
+const char *smack_smackfs_path(void)
+{
+       return smack_mnt;
+}
+
+int smack_cipso_apply(struct smack_cipso *cipso)
+{
+       struct cipso_mapping *m = NULL;
+       char buf[CIPSO_MAX_SIZE];
+       int fd;
+       int i;
+       char path[PATH_MAX];
+
+       if (!smack_mnt) {
+               errno = EFAULT;
+               return -1; 
+       }
+       
+       snprintf(path, sizeof path, "%s/cipso2", smack_mnt);
+       fd = open(path, O_WRONLY);
+       if (fd < 0)
+               return -1;
+
+       for (m = cipso->first; m != NULL; m = m->next) {
+               sprintf(buf, "%s ", m->label);
+               sprintf(&buf[SMACK_LABEL_LEN + 1], CIPSO_NUM_LEN_STR, m->level);
+               sprintf(&buf[SMACK_LABEL_LEN + 1 + NUM_LEN], CIPSO_NUM_LEN_STR, m->ncats);
+
+               for (i = 0; i < m->ncats; i++)
+                       sprintf(&buf[CIPSO_POS(i)], CIPSO_NUM_LEN_STR, m->cats[i]);
+
+               if (write(fd, buf, strlen(buf)) < 0) {
+                       close(fd);
+                       return -1;
+               }
+       }
+
+       close(fd);
+       return 0;
+}
+
+int smack_new_label_from_self(char **label)
+{
+       char *result;
+       int fd;
+       int ret;
+
+       result = calloc(SMACK_LABEL_LEN + 1, 1);
+       if (result == NULL)
+               return -1;
+
+       fd = open(SELF_LABEL_FILE, O_RDONLY);
+       if (fd < 0) {
+               free(result);
+               return -1;
+       }
+
+       ret = read(fd, result, SMACK_LABEL_LEN);
+       close(fd);
+       if (ret < 0) {
+               free(result);
+               return -1;
+       }
+
+       *label = result;
+       return 0;
+}
+
+int smack_new_label_from_socket(int fd, char **label)
+{
+       char dummy;
+       int ret;
+       socklen_t length = 1;
+       char *result;
+
+       ret = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, &dummy, &length);
+       if (ret < 0 && errno != ERANGE)
+               return -1;
+
+       result = calloc(length + 1, 1);
+       if (result == NULL)
+               return -1;
+
+       ret = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, result, &length);
+       if (ret < 0) {
+               free(result);
+               return -1;
+       }
+
+       *label = result;
+       return 0;
+}
+
+int smack_set_label_for_self(const char *label)
+{
+       int len;
+       int fd;
+       int ret;
+
+       len = strnlen(label, SMACK_LABEL_LEN + 1);
+       if (len > SMACK_LABEL_LEN)
+               return -1;
+
+       fd = open(SELF_LABEL_FILE, O_WRONLY);
+       if (fd < 0)
+               return -1;
+
+       ret = write(fd, label, len);
+       close(fd);
+
+       return (ret < 0) ? -1 : 0;
+}
+
+int smack_revoke_subject(const char *subject)
+{
+       int ret;
+       int fd;
+       int len;
+       char path[PATH_MAX];
+
+       len = strnlen(subject, SMACK_LABEL_LEN + 1);
+       if (len > SMACK_LABEL_LEN)
+               return -1;
+
+       snprintf(path, sizeof path, "%s/revoke-subject", smack_mnt);
+       fd = open(path, O_WRONLY);
+       if (fd < 0)
+               return -1;
+
+       ret = write(fd, subject, len);
+       close(fd);
+
+       return (ret < 0) ? -1 : 0;
+}
+
+static int internal_getlabel(void* file, char** label,
+               enum smack_label_type type,
+               getxattr_func getfunc)
+{
+       char* xattr_name = get_xattr_name(type);
+       char value[SMACK_LABEL_LEN + 1];
+       int ret;
+
+       ret = getfunc(file, xattr_name, value, SMACK_LABEL_LEN + 1);
+       if (ret == -1) {
+               if (errno == ENODATA) {
+                       *label = NULL;
+                       return 0;
+               }
+               return -1;
+       }
+
+       value[ret] = '\0';
+       *label = calloc(ret + 1, 1);
+       if (*label == NULL)
+               return -1;
+       strncpy(*label, value, ret);
+       return 0;
+}
+
+static int internal_setlabel(void* file, const char* label,
+               enum smack_label_type type,
+               setxattr_func setfunc, removexattr_func removefunc)
+{
+       char* xattr_name = get_xattr_name(type);
+       int ret;
+
+       /* Check validity of labels for LABEL_TRANSMUTE */
+       if (type == SMACK_LABEL_TRANSMUTE && label != NULL) {
+               if (!strcmp(label, "0"))
+                       label = NULL;
+               else if (!strcmp(label, "1"))
+                       label = "TRUE";
+               else
+                       return -1;
+       }
+
+       if (label == NULL || label[0] == '\0') {
+               ret = removefunc(file, xattr_name);
+               if (ret == -1 && errno == ENODATA)
+                       return 0;
+               return ret;
+       } else {
+               int len = strnlen(label, SMACK_LABEL_LEN + 1);
+               if (len > SMACK_LABEL_LEN)
+                       return -1;
+               return setfunc(file, xattr_name, label, len, 0);
+       }
+}
+
+int smack_getlabel(const char *path, char** label,
+               enum smack_label_type type)
+{
+       return internal_getlabel((void*) path, label, type,
+                       (getxattr_func) getxattr);
+}
+
+int smack_lgetlabel(const char *path, char** label,
+               enum smack_label_type type)
+{
+       return internal_getlabel((void*) path, label, type,
+                       (getxattr_func) lgetxattr);
+}
+
+int smack_fgetlabel(int fd, char** label,
+               enum smack_label_type type)
+{
+       return internal_getlabel((void*) fd, label, type,
+                       (getxattr_func) fgetxattr);
+}
+
+int smack_setlabel(const char *path, const char* label,
+               enum smack_label_type type)
+{
+       return internal_setlabel((void*) path, label, type,
+                       (setxattr_func) setxattr, (removexattr_func) removexattr);
+}
+
+int smack_lsetlabel(const char *path, const char* label,
+               enum smack_label_type type)
+{
+       return internal_setlabel((void*) path, label, type,
+                       (setxattr_func) lsetxattr, (removexattr_func) lremovexattr);
+}
+
+int smack_fsetlabel(int fd, const char* label,
+               enum smack_label_type type)
+{
+       return internal_setlabel((void*) fd, label, type,
+                       (setxattr_func) fsetxattr, (removexattr_func) fremovexattr);
+}
+
+static int accesses_apply(struct smack_accesses *handle, int clear)
+{
+       char buf[LOAD_LEN + 1];
+       struct smack_rule *rule;
+       int ret;
+       int fd;
+       int load_fd;
+       int change_fd;
+       int load2 = 1;
+       char path[PATH_MAX];
+
+       if (!smack_mnt) {
+               errno = EFAULT;
+               return -1; 
+       }
+       
+       snprintf(path, sizeof path, "%s/load2", smack_mnt);
+       load_fd = open(path, O_WRONLY);
+       if (load_fd < 0) {
+               if (errno != ENOENT)
+                       return -1;
+               /* fallback */
+               snprintf(path, sizeof path, "%s/load", smack_mnt);
+               load_fd = open(path, O_WRONLY);
+               /* Try to continue if the file doesn't exist, we might not need it. */
+               if (load_fd < 0 && errno != ENOENT)
+                       return -1;
+               load2 = 0;
+       }
+
+       snprintf(path, sizeof path, "%s/change-rule", smack_mnt);
+       change_fd = open(path, O_WRONLY);
+       /* Try to continue if the file doesn't exist, we might not need it. */
+       if (change_fd < 0 && errno != ENOENT) {
+               ret = -1;
+               goto err_out;
+       }
+
+       for (rule = handle->first; rule != NULL; rule = rule->next) {
+               if (clear) {
+                       strcpy(rule->access_set, "-----");
+                       rule->is_modify = 0;
+               }
+
+               if (rule->is_modify) {
+                       fd = change_fd;
+                       ret = snprintf(buf, LOAD_LEN + 1, KERNEL_MODIFY_FORMAT,
+                                               rule->subject, rule->object,
+                                               rule->access_add, rule->access_del);
+               } else {
+                       fd = load_fd;
+                       if (load2)
+                               ret = snprintf(buf, LOAD_LEN + 1, KERNEL_LONG_FORMAT,
+                                              rule->subject, rule->object,
+                                              rule->access_set);
+                       else
+                               ret = snprintf(buf, LOAD_LEN + 1, KERNEL_SHORT_FORMAT,
+                                              rule->subject, rule->object,
+                                              rule->access_set);
+               }
+
+               if (ret < 0 || fd < 0) {
+                       ret = -1;
+                       goto err_out;
+               }
+
+               ret = write(fd, buf, strlen(buf));
+               if (ret < 0) {
+                       ret = -1;
+                       goto err_out;
+               }
+       }
+       ret = 0;
+
+err_out:
+       if (load_fd >= 0)
+               close(load_fd);
+       if (change_fd >= 0)
+               close(change_fd);
+       return ret;
+}
+
+static inline void parse_access_type(const char *in, char out[ACC_LEN + 1])
+{
+       int i;
+
+       for (i = 0; i < ACC_LEN; ++i)
+               out[i] = '-';
+       out[ACC_LEN] = '\0';
+
+       for (i = 0; in[i] != '\0'; i++)
+               switch (in[i]) {
+               case 'r':
+               case 'R':
+                       out[0] = 'r';
+                       break;
+               case 'w':
+               case 'W':
+                       out[1] = 'w';
+                       break;
+               case 'x':
+               case 'X':
+                       out[2] = 'x';
+                       break;
+               case 'a':
+               case 'A':
+                       out[3] = 'a';
+                       break;
+               case 't':
+               case 'T':
+                       out[4] = 't';
+                       break;
+               default:
+                       break;
+               }
+}
+
+static inline char* get_xattr_name(enum smack_label_type type)
+{
+       switch (type) {
+       case SMACK_LABEL_ACCESS:
+               return "security.SMACK64";
+       case SMACK_LABEL_EXEC:
+               return "security.SMACK64EXEC";
+       case SMACK_LABEL_MMAP:
+               return "security.SMACK64MMAP";
+       case SMACK_LABEL_TRANSMUTE:
+               return "security.SMACK64TRANSMUTE";
+       case SMACK_LABEL_IPIN:
+               return "security.SMACK64IPIN";
+       case SMACK_LABEL_IPOUT:
+               return "security.SMACK64IPOUT";
+       default:
+               /* Should not reach this point */
+               return NULL;
+       }
+
+}
index 275a1a4d550bbeca954d257e61eae93c592ab5de..c187d30fa8538e241e191880dc9b5b66d20276d9 100644 (file)
@@ -35,6 +35,7 @@
 
 #define HAVE_PTHREADS
 #include <stdio.h>
+#include "strutils.h"
 #include "threads.h"
 
 static mutex_t  env_lock = MUTEX_INITIALIZER;
@@ -51,7 +52,6 @@ struct config_node {
 };
 
 void property_save();
-int read_line(const int fd, char* ptr, const unsigned int maxlen);
 
 static void property_init(void)
 {
@@ -153,25 +153,6 @@ int property_list(void (*propfn)(const char *key, const char *value, void *cooki
     return 0;
 }
 
-int read_line(const int fd, char* ptr, const unsigned int maxlen)
-{
-    unsigned int n = 0;
-    char c[2];
-    int rc;
-
-    while(n != maxlen) {
-        if((rc = sdb_read(fd, c, 1)) != 1)
-            return -1; // eof or read err
-
-        if(*c == '\n') {
-            ptr[n] = 0;
-            return n;
-        }
-        ptr[n++] = *c;
-    }
-    return -1; // no space
-}
-
 #elif defined(HAVE_LIBC_SYSTEM_PROPERTIES)
 
 #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
index 49fd90e01a0c224ecba043ca027df786199dad05..fea30f4fb1946cdf60850efcc31005d139872548 100644 (file)
--- a/src/sdb.c
+++ b/src/sdb.c
@@ -25,6 +25,7 @@
 #include <time.h>
 #include <sys/time.h>
 #include <signal.h>
+#include <grp.h>
 
 #include "sysdeps.h"
 #include "sdb.h"
@@ -44,7 +45,6 @@ SDB_MUTEX_DEFINE( D_lock );
 
 int HOST = 0;
 
-
 void handle_sig_term(int sig) {
 #ifdef SDB_PIDPATH
     if (access(SDB_PIDPATH, F_OK) == 0)
@@ -110,6 +110,7 @@ void  sdb_trace_init(void)
         { "jdwp", TRACE_JDWP },
         { "services", TRACE_SERVICES },
         { "properties", TRACE_PROPERTIES },
+        { "sdktools", TRACE_SDKTOOLS },
         { NULL, 0 }
     };
 
@@ -965,48 +966,74 @@ void build_local_name(char* target_str, size_t target_size, int server_port)
   snprintf(target_str, target_size, "tcp:%d", server_port);
 }
 
-#if 0
 #if !SDB_HOST
-static int should_drop_privileges() {
-#ifndef ALLOW_SDBD_ROOT
+static void init_drop_privileges() {
+#ifdef _DROP_PRIVILEGE
+    rootshell_mode = 0;
+#else
+    rootshell_mode = 1;
+#endif
+}
+
+int should_drop_privileges() {
+    if (rootshell_mode == 1) { // if root, then don't drop
+        return 0;
+    }
     return 1;
-#else /* ALLOW_SDBD_ROOT */
-    int secure = 0;
-    char value[PROPERTY_VALUE_MAX];
-
-   /* run sdbd in secure mode if ro.secure is set and
-    ** we are not in the emulator
-    */
-    property_get("ro.kernel.qemu", value, "");
-    if (strcmp(value, "1") != 0) {
-        property_get("ro.secure", value, "1");
-        if (strcmp(value, "1") == 0) {
-            // don't run as root if ro.secure is set...
-            secure = 1;
-
-            // ... except we allow running as root in userdebug builds if the
-            // service.sdb.root property has been set by the "sdb root" command
-            property_get("ro.debuggable", value, "");
-            if (strcmp(value, "1") == 0) {
-                property_get("service.sdb.root", value, "");
-                if (strcmp(value, "1") == 0) {
-                    secure = 0;
-                }
-            }
+}
+
+int set_developer_privileges() {
+    gid_t groups[] = { SID_DEVELOPER, SID_APP_LOGGING, SID_SYS_LOGGING };
+    if (setgroups(sizeof(groups) / sizeof(groups[0]), groups) != 0) {
+        fprintf(stderr, "set groups failed (errno: %d, %s)\n", errno, strerror(errno));
+        //exit(1);
+    }
+
+    // then switch user and group to developer
+    if (setgid(SID_DEVELOPER) != 0) {
+        fprintf(stderr, "set group id failed (errno: %d, %s)\n", errno, strerror(errno));
+        //exit(1);
+        return -1;
+    }
+
+    if (setuid(SID_DEVELOPER) != 0) {
+        fprintf(stderr, "set user id failed (errno: %d, %s)\n", errno, strerror(errno));
+        //exit(1);
+        return -1;
+    }
+
+    if (chdir("/home/developer") < 0) {
+        D("sdbd: unable to change working directory to /home/developer\n");
+    } else {
+        if (chdir("/") < 0) {
+            D("sdbd: unable to change working directory to /\n");
+        }
+    }
+    return 1;
+}
+#define ONDEMAND_PATH "/home/developer/sdk_tools"
+
+static void init_sdk_requirements() {
+    struct stat st;
+    if (stat(ONDEMAND_PATH, &st) == -1) {
+        return;
+    }
+    if (st.st_uid != SID_DEVELOPER || st.st_gid != SID_DEVELOPER) {
+        char cmd[128];
+        snprintf(cmd, sizeof(cmd), "chown developer:developer %s -R", ONDEMAND_PATH);
+        if (system(cmd) < 0) {
+            D("failed to change ownership to developer to %s\n",ONDEMAND_PATH);
         }
     }
-    return secure;
-#endif /* ALLOW_SDBD_ROOT */
 }
 #endif /* !SDB_HOST */
-#endif
 
 int sdb_main(int is_daemon, int server_port)
 {
 #if !SDB_HOST
-    int port;
-    char value[PROPERTY_VALUE_MAX];
 
+    init_drop_privileges();
+    init_sdk_requirements();
     umask(000);
 #endif
 
@@ -1033,41 +1060,31 @@ int sdb_main(int is_daemon, int server_port)
         exit(1);
     }
 #else
-#if 0 /* tizen specific */
     /* don't listen on a port (default 5037) if running in secure mode */
     /* don't run as root if we are running in secure mode */
+
     if (should_drop_privileges()) {
+# if 0
         struct __user_cap_header_struct header;
         struct __user_cap_data_struct cap;
 
         if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) {
             exit(1);
         }
-
         /* add extra groups:
-        ** AID_SDB to access the USB driver
-        ** AID_LOG to read system logs (sdb logcat)
-        ** AID_INPUT to diagnose input issues (getevent)
-        ** AID_INET to diagnose network issues (netcfg, ping)
-        ** AID_GRAPHICS to access the frame buffer
-        ** AID_NET_BT and AID_NET_BT_ADMIN to diagnose bluetooth (hcidump)
-        ** AID_SDCARD_R to allow reading from the SD card
-        ** AID_SDCARD_RW to allow writing to the SD card
-        ** AID_MOUNT to allow unmounting the SD card before rebooting
-        ** AID_NET_BW_STATS to read out qtaguid statistics
+        ** SID_TTY to access /dev/ptmx
         */
-        gid_t groups[] = { AID_SDB, AID_LOG, AID_INPUT, AID_INET, AID_GRAPHICS,
-                           AID_NET_BT, AID_NET_BT_ADMIN, AID_SDCARD_R, AID_SDCARD_RW,
-                           AID_MOUNT, AID_NET_BW_STATS };
+        gid_t groups[] = { SID_TTY, SID_APP_LOGGING, SID_SYS_LOGGING };
         if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) {
             exit(1);
         }
-
-        /* then switch user and group to "shell" */
-        if (setgid(AID_SHELL) != 0) {
+        /* then switch user and group to "developer" */
+        if (setgid(SID_DEVELOPER) != 0) {
+            fprintf(stderr, "set group id failed errno: %d\n", errno);
             exit(1);
         }
-        if (setuid(AID_SHELL) != 0) {
+        if (setuid(SID_DEVELOPER) != 0) {
+            fprintf(stderr, "set user id failed errno: %d\n", errno);
             exit(1);
         }
 
@@ -1077,34 +1094,21 @@ int sdb_main(int is_daemon, int server_port)
         cap.effective = cap.permitted = (1 << CAP_SYS_BOOT);
         cap.inheritable = 0;
         capset(&header, &cap);
-
+#endif
         D("Local port disabled\n");
     } else {
-#endif
         char local_name[30];
         build_local_name(local_name, sizeof(local_name), server_port);
         if(install_listener(local_name, "*smartsocket*", NULL)) {
             exit(1);
         }
-#if 0 /* tizen specific */
     }
-#endif
-        /* for the device, start the usb transport if the
-        ** android usb device exists and the "service.sdb.tcp.port" and
-        ** "persist.sdb.tcp.port" properties are not set.
-        ** Otherwise start the network transport.
-        */
-    property_get("service.sdb.tcp.port", value, "");
-#if 0 /* tizen specific */
-    if (!value[0])
-        property_get("persist.sdb.tcp.port", value, "");
-#endif
-    if (sscanf(value, "%d", &port) == 1 && port > 0) {
-        // listen on TCP port specified by service.sdb.tcp.port property
-        local_init(port);
-    } else if (access("/dev/samsung_sdb", F_OK) == 0) {
+
+    if (access("/dev/samsung_sdb", F_OK) == 0) {
         // listen on USB
         usb_init();
+        // listen on tcp
+        local_init(DEFAULT_SDB_LOCAL_TRANSPORT_PORT);
     } else {
         // listen on default port
         local_init(DEFAULT_SDB_LOCAL_TRANSPORT_PORT);
index a6a052dccdf19be7502b2336efdff8da0944d8b6..41ce73475965f94c8c96379718e5a039fb72da99 100644 (file)
--- a/src/sdb.h
+++ b/src/sdb.h
@@ -33,9 +33,9 @@
 #define A_VERSION 0x01000000        // SDB protocol version
 
 #define SDB_VERSION_MAJOR 2         // Used for help/version information
-#define SDB_VERSION_MINOR 0         // Used for help/version information
+#define SDB_VERSION_MINOR 1         // Used for help/version information
 
-#define SDB_SERVER_VERSION 2        // Increment this when we want to force users to start a new sdb server
+#define SDB_SERVER_VERSION 0        // Increment this when we want to force users to start a new sdb server
 
 typedef struct amessage amessage;
 typedef struct apacket apacket;
@@ -319,8 +319,24 @@ void framebuffer_service(int fd, void *cookie);
 void log_service(int fd, void *cookie);
 void remount_service(int fd, void *cookie);
 char * get_log_file_path(const char * log_name);
+
+int rootshell_mode;// 0: developer, 1: root
+
+// This is the users and groups config for the platform
+
+#define SID_ROOT        0    /* traditional unix root user */
+#define SID_TTY         5    /* group for /dev/ptmx */
+#define SID_APP         5000 /* application */
+#define SID_DEVELOPER   5100 /* developer with SDK */
+#define SID_APP_LOGGING 6509
+#define SID_SYS_LOGGING 6527
+
 #endif
 
+int should_drop_privileges(void);
+int set_developer_privileges();
+void set_root_privileges();
+
 /* packet allocator */
 apacket *get_apacket(void);
 void put_apacket(apacket *p);
@@ -347,7 +363,8 @@ typedef enum {
     TRACE_SYSDEPS,
     TRACE_JDWP,
     TRACE_SERVICES,
-    TRACE_PROPERTIES
+    TRACE_PROPERTIES,
+    TRACE_SDKTOOLS
 } SdbTrace;
 
 #if SDB_TRACE
diff --git a/src/sdktools.c b/src/sdktools.c
new file mode 100644 (file)
index 0000000..16e40f4
--- /dev/null
@@ -0,0 +1,412 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <grp.h>
+#include <regex.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "sysdeps.h"
+#include "smack.h"
+#include "sdktools.h"
+
+#define  TRACE_TAG  TRACE_SERVICES
+#include "sdb.h"
+#include "sdktools.h"
+#include "strutils.h"
+#include "fileutils.h"
+
+struct sudo_command root_commands[] = {
+    /* 0 */ {"killall", "/usr/bin/killall"},
+    /* 1 */ {"pkgcmd", "/usr/bin/pkgcmd"},
+    /* 2 */ {"launch_app", "/usr/bin/launch_app"},
+    /* 3 */ {"dlogutil", "/usr/bin/dlogutil"},
+    /* 4 */ {"zypper", "/usr/bin/zypper"},
+    /* 5 */ {"pkginfo", "/usr/bin/pkginfo"},
+    /* 6 */ {"da_command", "/usr/bin/da_command"},
+    /* 7 */ {"oprofile", "/usr/bin/oprofile_command"},
+    /* 8 */ {"wrt-launcher", "/usr/bin/wrt-launcher"},
+    /* end */ {NULL, NULL}
+};
+
+struct arg_permit_rule sdk_arg_permit_rule[] = {
+    /* 2 */ {"gcove_env1", "^GCOV_PREFIX=((/opt/apps)|(/opt/usr/apps))/[a-zA-Z0-9]{10}/data$", 1},
+    /* 2 */ {"gcove_env2", "GCOV_PREFIX_STRIP=0", 0},
+    /* 2 */ {"gcove_env3", "LD_LIBRARY_PATH=/home/developer/sdk_tools/gtest/usr/lib:$LD_LIBRARY_PATH", 0},
+    /* 2 */ {"gcove_env4", "TIZEN_LAUNCH_MODE=debug", 0},
+    /* 2 */ {"da_env1", "LD_PRELOAD=/usr/lib/da_probe_osp.so", 0},
+    /* 2 */ {"gcove_arg1", "^\\-\\-gtest_output=xml:((/opt/apps)|(/opt/usr/apps))/[a-zA-Z0-9]{10}/data/[a-zA-Z0-9_\\-]{1,30}\\.xml$", 1},
+    /* end */ {NULL, NULL, 0}
+};
+
+int verify_commands(const char *arg1) {
+    if (arg1 != NULL) {
+        if (verify_root_commands(arg1)) {
+            // do not drop privilege only if root auth is required
+            return 1;
+        }
+    }
+    // doing these steps if we don't have root permission
+    if (should_drop_privileges()) {
+        set_developer_privileges();
+    }
+    return 1;
+}
+
+/**
+ * Returns 1 if the command is root, otherwise 0.
+ */
+int verify_root_commands(const char *arg1) {
+    char *tokens[MAX_TOKENS];
+    size_t cnt;
+    int ret = 0;
+    int index = -1;
+    int i = 0;
+
+    D("cmd processing......: %s\n", arg1);
+
+    cnt = tokenize(arg1, " ", tokens, MAX_TOKENS);
+    for (i=0; i<cnt; i++) {
+        D("tokenize: %dth: %s\n", i, tokens[i]);
+    }
+    if (cnt == 0 ) {
+        return 0; // just keep going to execute normal commands
+    }
+    index = is_root_commands(tokens[0]);
+    if (index == -1) {
+        if (exec_app_standalone(arg1)) {
+            ret = 1;
+        } else {
+            return 0; // just keep going to execute normal commands
+        }
+    }
+
+    switch (index) {
+    case 0: {
+        if (cnt == 2) {
+            if (verify_app_path(tokens[1])) {
+                ret = 1;
+            }
+        }
+        break;
+    }
+    case 1: {
+        ret = 1;
+        break;
+    }
+    case 2: {
+        ret = 1;
+        break;
+    }
+    case 3: {
+        ret = 1;
+        break;
+    }
+    case 4: {
+        ret = 1;
+        break;
+    }
+    case 5: {
+        ret = 1;
+        break;
+    }
+    case 6: {
+        ret = 1;
+        break;
+    }
+    case 7: {
+        ret = 1;
+        break;
+    }
+    case 8: {
+        ret = 1;
+        break;
+    }
+    default: {
+        break;
+    }
+    }
+
+    D("doing the cmd as a %s\n", ret == 1 ? "root" : "developer");
+
+    if (cnt) {
+        free_strings(tokens, cnt);
+    }
+
+    return ret;
+}
+
+int verify_app_path(const char* path) {
+    char buf[PATH_MAX];
+
+    snprintf(buf, sizeof buf, "^((%s)|(%s))/[a-zA-Z0-9]{%d}/bin/[a-zA-Z0-9_\\-]{1,}(\\.exe)?$", APP_INSTALL_PATH_PREFIX1, APP_INSTALL_PATH_PREFIX2, APPID_MAX_LENGTH);
+    return regcmp(buf, path);
+}
+
+int regcmp(const char* pattern, const char* str) {
+    regex_t regex;
+    int ret;
+
+    ret = regcomp(&regex, pattern, REG_EXTENDED);
+    if(ret){ // not match
+        return 0;
+    }
+
+    // execute regular expression
+    ret = regexec(&regex, str, 0, NULL, 0);
+    if(!ret){
+        regfree(&regex);
+        return 1;
+    } else if( ret == REG_NOMATCH ){
+        //D("not valid application path\n");
+    } else{
+        //regerror(ret, &regex, buf, sizeof(buf));
+        //D("regex match failed: %s\n", buf);
+    }
+    regfree(&regex);
+    return 0;
+}
+
+int env_verify(const char* arg) {
+    int i;
+    for (i=0; sdk_arg_permit_rule[i].name != NULL; i++) {
+        if (sdk_arg_permit_rule[i].expression == 0) {
+            if (!strcmp(sdk_arg_permit_rule[i].pattern, arg)) {
+                D("success to set %s\n", arg);
+                return 1;
+            }
+        } else if (sdk_arg_permit_rule[i].expression == 1) {
+            if (regcmp(sdk_arg_permit_rule[i].pattern, arg)) {
+                D("success to set %s\n", arg);
+                return 1;
+            }
+        }
+    }
+    D("failed to set %s\n", arg);
+    return 0;
+}
+
+int exec_app_standalone(const char* path) {
+    char *tokens[MAX_TOKENS];
+    int ret = 0;
+    int cnt = 0;
+    int flag = 1;
+    int i=0;
+
+    cnt = tokenize(path, " ", tokens, MAX_TOKENS);
+    for (i=0; i<cnt; i++) {
+        D("tokenize: %dth: %s\n", i, tokens[i]);
+
+        if (!strcmp("export", tokens[i])) {
+            flag = 0;
+            i++;
+            if (i>=cnt) break;
+            if (env_verify(tokens[i])) {
+                flag = 1;
+            }
+            i++;
+            if (i>=cnt) break;
+            if (!strcmp("&&", tokens[i])) {
+                continue;
+            }
+        }
+        if (flag == 0) {
+            // TODO: check evn setting
+        }
+        // TODO: i length check
+        if (!strcmp(tokens[i], GDBSERVER_PATH)) { //gdbserver :11 --attach 2332 (cnt=4,)
+            char *gdb_attach_arg_pattern = "^:[1-9][0-9]{2,5} \\-\\-attach [1-9][0-9]{2,5}$";
+            int argcnt = cnt-i-1;
+            if (argcnt == 3 && !strcmp("--attach", tokens[i+2])) {
+                char cmdline[128];
+                int pid = 0;
+                D("parsing.... debug attach mode\n");
+                snprintf(cmdline, sizeof(cmdline), "%s %s %s",tokens[i+1], tokens[i+2], tokens[i+3]);
+                if (regcmp(gdb_attach_arg_pattern, cmdline)) {
+                    char cmdline[128];
+                    pid = atoi(tokens[i+3]);
+                    if (pid) {
+                        snprintf(cmdline, sizeof(cmdline), "/proc/%d/cmdline", pid);
+                        int fd = unix_open(cmdline, O_RDONLY);
+                        if (fd) {
+                            if(read_line(fd, cmdline, sizeof(cmdline))) {
+                                if (set_smack_rules_for_gdbserver(cmdline, 1)) {
+                                    ret = 1;
+                                }
+                            }
+                            sdb_close(fd);
+                        }
+                    }
+                }
+            }
+            if (argcnt >= 2 && verify_app_path(tokens[i+2])) {
+                D("parsing.... debug run as mode\n");
+                if (set_smack_rules_for_gdbserver(tokens[i+2], 0)) {
+                    ret = 1;
+                }
+            }
+            D("finished debug launch mode\n");
+        } else {
+            if (verify_app_path(tokens[i])) {
+                char *path = tokens[i];
+                char *appid = NULL;
+                int rc = smack_lgetlabel(path, &appid, SMACK_LABEL_ACCESS);
+                if (rc == 0 && appid != NULL) {
+                    if (smack_set_label_for_self(appid) != -1) {
+                        D("set smack lebel [%s] appid to %s\n", appid, SMACK_LEBEL_SUBJECT_PATH);
+                        apply_app_process();
+                        ret = 1;
+                    } else {
+                        D("unable to open %s due to %s\n", SMACK_LEBEL_SUBJECT_PATH, strerror(errno));
+                    }
+                    free(appid);
+                }
+                D("standalone launch\n");
+            }
+        }
+        // TODO: verify arguments
+        break;
+    }
+
+    if (cnt) {
+        free_strings(tokens, cnt);
+    }
+    return ret;
+}
+
+/**
+ * free after use it
+ */
+char* clone_gdbserver_label_from_app(const char* app_path) {
+    char *new_appid = NULL;
+    char appid[APPID_MAX_LENGTH+1];
+    char *buffer = NULL;
+
+    if (!verify_app_path(app_path)) {
+        D("not be able to access %s\n", app_path);
+        return NULL;
+    }
+
+    int rc = smack_lgetlabel(app_path, &buffer, SMACK_LABEL_ACCESS);
+
+    if (rc == 0 && buffer != NULL && strlen(buffer) == APPID_MAX_LENGTH) {
+        strcpy(appid, buffer);
+        free(buffer);
+    } else {
+        strcpy(appid, "_");
+    }
+    new_appid = (char *)malloc(sizeof(appid)+1);
+    strncpy(new_appid, appid, APPID_MAX_LENGTH);
+    // Do not label to gdbserver executable
+/*
+    if (new_appid != NULL) {
+        rc = smack_lsetlabel(GDBSERVER_PATH, new_appid, SMACK_LABEL_ACCESS);
+        if (rc < 0) {
+            D("unable to set access smack label: %s to %s\n", GDBSERVER_PATH, new_appid);
+        }
+        D("set access smack label: %s to %s\n", GDBSERVER_PATH, new_appid);
+
+        rc = smack_lsetlabel(GDBSERVER_PATH, new_appid, SMACK_LABEL_EXEC);
+        if (rc < 0) {
+            D("unable to set execute smack label: %s to %s\n", GDBSERVER_PATH, new_appid);
+        }
+        D("set execute smack label: %s to %s\n", GDBSERVER_PATH, new_appid);
+    }
+*/
+    return new_appid;
+}
+
+int set_smack_rules_for_gdbserver(const char* apppath, int mode) {
+    // FIXME: set gdbfolder to 755 also
+    if(sdb_chmod(GDBSERVER_PATH, S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH, 1) < 0)
+    {
+        D("unable to set 755 to %s", GDBSERVER_PATH);
+    }
+
+    // in case of debug as mode
+    char *new_appid = clone_gdbserver_label_from_app(apppath);
+    if (new_appid != NULL) {
+        if (smack_set_label_for_self(new_appid) != -1) {
+            D("set smack lebel [%s] appid to %s\n", new_appid, SMACK_LEBEL_SUBJECT_PATH);
+            // apply app precess only if not attach mode
+            if (mode == 0) {
+                apply_app_process();
+            }
+        } else {
+            D("unable to open %s due to %s\n", SMACK_LEBEL_SUBJECT_PATH, strerror(errno));
+        }
+        free(new_appid);
+        return 1;
+    }
+    // TODO: in case of attach mode
+    return 0;
+}
+
+void apply_app_process() {
+    set_appuser_groups();
+
+    if (setgid(SID_APP) != 0) {
+        fprintf(stderr, "set group id failed errno: %d\n", errno);
+        exit(1);
+    }
+
+    if (setuid(SID_APP) != 0) {
+        fprintf(stderr, "set user id failed errno: %d\n", errno);
+        exit(1);
+    }
+}
+
+void set_appuser_groups(void) {
+
+    int fd = 0;
+    char buffer[5];
+    gid_t t_gid = -1;
+    gid_t groups[APP_GROUPS_MAX]={0,};
+    int cnt = 0;
+
+    //groups[cnt++] = SID_DEVELOPER;
+    fd = sdb_open(APP_GROUP_LIST, O_RDONLY);
+    if (fd < 0) {
+        D("cannot get app's group lists from %s", APP_GROUP_LIST);
+        return;
+    }
+    for (;;) {
+        if (read_line(fd, buffer, sizeof buffer) < 0) {
+            break;
+        }
+        t_gid = strtoul(buffer, 0, 10);
+        errno = 0;
+        if(errno != 0)
+        {
+            D("cannot change string to integer: [%s]\n", buffer);
+            continue;
+        }
+        if (t_gid) {
+            if (cnt < APP_GROUPS_MAX) {
+                groups[cnt++] = t_gid;
+            } else {
+                D("cannot add groups more than %d", APP_GROUPS_MAX);
+                break;
+            }
+        }
+    }
+    if (cnt > 0) {
+        if (setgroups(sizeof(groups) / sizeof(groups[0]), groups) != 0) {
+           fprintf(stderr, "set groups failed errno: %d\n", errno);
+           exit(1);
+        }
+    }
+}
+
+int is_root_commands(const char *command) {
+    int i = -1;
+    for(i = 0; root_commands[i].path != NULL; i++) {
+        if(!strncmp(root_commands[i].path, command, PATH_MAX)) {
+            return i;
+        }
+    }
+    // not found
+    return -1;
+}
diff --git a/src/sdktools.h b/src/sdktools.h
new file mode 100644 (file)
index 0000000..34f2ecb
--- /dev/null
@@ -0,0 +1,49 @@
+#ifndef _SDKTOOLS_H
+#define _SDKTOOLS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct sudo_command
+{
+  const char *command;
+  const char *path;
+  //const char *arguments;
+  //const char *regx;
+  //int   permission; /* 0: root, 1: developer, 2: app*/
+};
+
+
+struct arg_permit_rule
+{
+    const char *name;
+    const char *pattern;
+    int expression; // 0:compare, 1: regx
+};
+
+
+#define APP_INSTALL_PATH_PREFIX1                "/opt/apps"
+#define APP_INSTALL_PATH_PREFIX2                "/opt/usr/apps"
+#define GDBSERVER_PATH                          "/home/developer/sdk_tools/gdbserver/gdbserver"
+#define SMACK_LEBEL_SUBJECT_PATH                "/proc/self/attr/current"
+#define APP_GROUPS_MAX                          100
+#define APP_GROUP_LIST                          "/usr/share/privilege-control/app_group_list"
+#define APPID_MAX_LENGTH                        10
+
+int verify_commands(const char *arg1);
+int verify_root_commands(const char *arg1);
+int verify_app_path(const char* path);
+int regcmp(const char* pattern, const char* str);
+int exec_app_standalone(const char* path);
+char* clone_gdbserver_label_from_app(const char* app_path);
+int set_smack_rules_for_gdbserver(const char* apppath, int mode);
+void apply_app_process();
+void set_appuser_groups(void);
+int is_root_commands(const char *command);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
index f31bf8343f436513ccebb6968aeb2afef065c7ab..2ecaacc0eb14e04db0b477d3d5e0a0e869f9dd75 100644 (file)
@@ -19,6 +19,7 @@
 #include <unistd.h>
 #include <string.h>
 #include <errno.h>
+#include <grp.h>
 
 #include "sysdeps.h"
 
@@ -35,6 +36,7 @@
 #else
 #   include "android_reboot.h"
 #   include <sys/inotify.h>
+#   include "sdktools.h"
 #endif
 
 typedef struct stinfo stinfo;
@@ -156,6 +158,39 @@ void restart_tcp_service(int fd, void *cookie)
     sdb_close(fd);
 }
 
+void rootshell_service(int fd, void *cookie)
+{
+    char buf[100];
+    char *mode = (char*) cookie;
+
+    if (!strcmp(mode, "on")) {
+        if (rootshell_mode == 1) {
+            //snprintf(buf, sizeof(buf), "Already changed to developer mode\n");
+            // do not show message
+        } else {
+            if (access("/bin/su", F_OK) == 0) {
+                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));
+        }
+    } else if (!strcmp(mode, "off")) {
+        if (rootshell_mode == 1) {
+            rootshell_mode = 0;
+            snprintf(buf, sizeof(buf), "Switched to 'developer' account mode\n");
+            writex(fd, buf, strlen(buf));
+        }
+    } else {
+        snprintf(buf, sizeof(buf), "Unknown command option\n");
+        writex(fd, buf, strlen(buf));
+    }
+    D("set rootshell to %s\n", rootshell_mode == 1 ? "root" : "developer");
+    sdb_close(fd);
+}
+
 void restart_usb_service(int fd, void *cookie)
 {
     char buf[100];
@@ -297,7 +332,7 @@ static int create_service_thread(void (*func)(int, void *), void *cookie)
     int s[2];
 
     if(sdb_socketpair(s)) {
-        printf("cannot create service socket pair\n");
+        D("cannot create service socket pair\n");
         return -1;
     }
 
@@ -311,7 +346,7 @@ static int create_service_thread(void (*func)(int, void *), void *cookie)
         free(sti);
         sdb_close(s[0]);
         sdb_close(s[1]);
-        printf("cannot create service thread\n");
+        D("cannot create service thread\n");
         return -1;
     }
 
@@ -320,6 +355,7 @@ static int create_service_thread(void (*func)(int, void *), void *cookie)
 }
 
 #if !SDB_HOST
+
 static int create_subprocess(const char *cmd, const char *arg0, const char *arg1, pid_t *pid)
 {
 #ifdef HAVE_WIN32_PROC
@@ -332,23 +368,23 @@ static int create_subprocess(const char *cmd, const char *arg0, const char *arg1
 
     ptm = unix_open("/dev/ptmx", O_RDWR); // | O_NOCTTY);
     if(ptm < 0){
-        printf("[ cannot open /dev/ptmx - %s ]\n",strerror(errno));
+        D("[ cannot open /dev/ptmx - %s ]\n",strerror(errno));
         return -1;
     }
     if (fcntl(ptm, F_SETFD, FD_CLOEXEC) < 0) {
-        printf("[ cannot set cloexec to /dev/ptmx - %s ]\n",strerror(errno));
+        D("[ cannot set cloexec to /dev/ptmx - %s ]\n",strerror(errno));
     }
 
     if(grantpt(ptm) || unlockpt(ptm) ||
        ((devname = (char*) ptsname(ptm)) == 0)){
-        printf("[ trouble with /dev/ptmx - %s ]\n", strerror(errno));
+        D("[ trouble with /dev/ptmx - %s ]\n", strerror(errno));
         sdb_close(ptm);
         return -1;
     }
 
     *pid = fork();
     if(*pid < 0) {
-        printf("- fork failed: %s -\n", strerror(errno));
+        D("- fork failed: %s -\n", strerror(errno));
         sdb_close(ptm);
         return -1;
     }
@@ -372,15 +408,21 @@ static int create_subprocess(const char *cmd, const char *arg0, const char *arg1
         sdb_close(ptm);
 
         // set OOM adjustment to zero
-        char text[64];
-        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 {
-           D("sdb: unable to open %s\n", text);
+        {
+            char text[64];
+            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 %s\n", text, strerror(errno));
+            }
         }
+
+        verify_commands(arg1);
+
         execl(cmd, cmd, arg0, arg1, NULL);
         fprintf(stderr, "- exec '%s' failed: %s (%d) -\n",
                 cmd, strerror(errno), errno);
@@ -528,7 +570,7 @@ int service_to_fd(const char *name)
             ret = create_subproc_thread(0);
         }
     } else if(!strncmp(name, "sync:", 5)) {
-        ret = create_service_thread(file_sync_service, NULL);
+        ret = create_service_thread(file_sync_subproc, NULL);
     }/*  else if(!strncmp(name, "remount:", 8)) {
         ret = create_service_thread(remount_service, NULL);
     } else if(!strncmp(name, "reboot:", 7)) {
@@ -543,7 +585,9 @@ int service_to_fd(const char *name)
         ret = backup_service(BACKUP, arg);
     } else if(!strncmp(name, "restore:", 8)) {
         ret = backup_service(RESTORE, NULL);
-    }*/ else if(!strncmp(name, "tcpip:", 6)) {
+    }*/ else if(!strncmp(name, "root:", 5)) {
+        ret = create_service_thread(rootshell_service, (void *)(name+5));
+    } else if(!strncmp(name, "tcpip:", 6)) {
         int port;
         /*if (sscanf(name + 6, "%d", &port) == 0) {
             port = 0;
diff --git a/src/smack.h b/src/smack.h
new file mode 100644 (file)
index 0000000..50504a5
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+ * This file is part of libsmack
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2011 Intel Corporation
+ * Copyright (C) 2012 Samsung Electronics Co.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * Authors:
+ * Jarkko Sakkinen <jarkko.sakkinen@intel.com>
+ * Rafal Krypa <r.krypa@samsung.com>
+ */
+
+/*!
+ * Smack user space library
+ */
+
+#ifndef _SYS_SMACK_H
+#define _SYS_SMACK_H
+
+#include <sys/types.h>
+
+/*!
+ * Maximum length of a smack label, excluding terminating null character.
+ */
+#define SMACK_LABEL_LEN 255
+
+enum smack_label_type {
+       SMACK_LABEL_ACCESS,
+       SMACK_LABEL_EXEC,
+       SMACK_LABEL_MMAP,
+       SMACK_LABEL_TRANSMUTE,
+       SMACK_LABEL_IPIN,
+       SMACK_LABEL_IPOUT,
+};
+
+/*!
+ * Handle to a in-memory representation of set of Smack rules.
+ */
+struct smack_accesses;
+
+/*!
+ *
+ */
+struct smack_cipso;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*!
+ * Creates a new empty smack_accesses instance.
+ *
+ * @param accesses created instance
+ * @return 0 on success and negative value on failure.
+ */
+int smack_accesses_new(struct smack_accesses **accesses);
+
+/*!
+ * Destroy a struct smack_accesses *instance.
+ *
+ * @param handle handle to a struct smack_accesses *instance
+ */
+void smack_accesses_free(struct smack_accesses *handle);
+
+/*!
+ * Write access rules to a given file.
+ *
+ * @param handle handle to a rules
+ * @param fd file descriptor
+ * @return 0 on success and negative value on failure.
+ */
+int smack_accesses_save(struct smack_accesses *handle, int fd);
+
+/*!
+ * Write rules to kernel.
+ *
+ * @param handle handle to a rules
+ * @return 0 on success and negative value on failure.
+ */
+int smack_accesses_apply(struct smack_accesses *handle);
+
+/*!
+ * Clear rules from kernel.
+ *
+ * @param handle handle to a rules
+ * @return 0 on success and negative value on failure.
+ */
+int smack_accesses_clear(struct smack_accesses *handle);
+
+/*!
+ * Add new rule to a rule set.
+ *
+ * @param handle handle to a rule set
+ * @param subject subject of the rule
+ * @param object object of the rule
+ * @param access_type access type
+ * @return Returns 0 on success.
+ */
+int smack_accesses_add(struct smack_accesses *handle, const char *subject,
+                      const char *object, const char *access_type);
+
+/*!
+ * Add a modification rule to a rule set.
+ * The modification rule will change access permissions for a given subject and
+ * object.
+ * If such rule already existend (in the kernel or earlier in the rule set),
+ * it will be modified. Otherwise a new rule will be created, with permissions
+ * from access_add minus permissions from access_del.
+ *
+ * @param handle handle to a rule set
+ * @param subject subject of the rule
+ * @param object object of the rule
+ * @param access_add access type
+ * @param access_del access type
+ * @return Returns 0 on success.
+ */
+int smack_accesses_add_modify(struct smack_accesses *handle, const char *subject,
+                      const char *object, const char *access_add, const char *access_del);
+
+/*!
+ * Add rules from file.
+ *
+ * @param accesses instance
+ * @param fd file descriptor
+ * @return 0 on success and negative value on failure.
+ */
+int smack_accesses_add_from_file(struct smack_accesses *accesses, int fd);
+
+/*!
+ * Check for Smack access.
+ *
+ * @param subject subject of the rule
+ * @param object object of the rule
+ * @param access_type access type
+ * @return 1 if access, 0 if no access and -1 on error.
+ */
+int smack_have_access(const char *subject, const char *object,
+                     const char *access_type);
+
+struct smack_cipso *smack_cipso_new(int fd);
+
+void smack_cipso_free(struct smack_cipso *cipso);
+
+int smack_cipso_apply(struct smack_cipso *cipso);
+
+/*!
+ * Get the smackfs directory.
+ */
+const char *smack_smackfs_path(void);
+
+/*!
+  * Get the label that is associated with the callers process.
+  * Caller is responsible of freeing the returned label.
+  *
+  * @param label returned label
+  * @return 0 on success and negative value on failure.
+  */
+int smack_new_label_from_self(char **label);
+
+/*!
+  * Get the label that is associated with a peer on the other end of an
+  * Unix socket (SO_PEERSEC). Caller is responsible of freeing the 
+  * returned label.
+  *
+  * @param fd socket file descriptor
+  * @param label returned label
+  * @return 0 on success and negative value on failure.
+  */
+int smack_new_label_from_socket(int fd, char **label);
+
+/*!
+ * Set the label associated with the callers process.
+ * Caller must be run by privileged user to succeed.
+ *
+ * @param label to set
+ * @return 0 on success and negative value on failure.
+ */
+int smack_set_label_for_self(const char *label);
+
+/*!
+ * Revoke all rules for a subject label.
+ *
+ * @param subject subject to revoke
+ * @return 0 on success and negative value on failure.
+ */
+int smack_revoke_subject(const char *subject);
+
+/*!
+ * Get SMACK label from file.
+ * On successful call label will be stored on allocated memory.
+ * Caller should take care of freeing that memory later.
+ *
+ * @param path file system path
+ * @param label returned label
+ * @param type label type to get
+ * @return 0 on success and negative value on failure.
+ */
+int smack_getlabel(const char *path, char** label,
+               enum smack_label_type type);
+
+/*!
+ * Get SMACK label from file. If path points to a symbolic link, the
+ * function will return label of the link instead of file it refers to.
+ * On successful call label will be stored on allocated memory.
+ * Caller should take care of freeing that memory later.
+ *
+ * @param path file system path
+ * @param label returned label
+ * @param type label type to get
+ * @return 0 on success and negative value on failure.
+ */
+int smack_lgetlabel(const char *path, char** label,
+               enum smack_label_type type);
+
+/*!
+ * Get SMACK label from file descriptor.
+ * On successful call label will be stored on allocated memory.
+ * Caller should take care of freeing that memory later.
+ *
+ * @param fd file descriptor
+ * @param label returned label
+ * @param type label type to get
+ * @return 0 on success and negative value on failure.
+ */
+int smack_fgetlabel(int fd, char** label,
+               enum smack_label_type type);
+
+/*!
+ * Set SMACK label for file.
+ * On successful call label will be stored on allocated memory.
+ *
+ * @param path file system path
+ * @param label SMACK label to set
+ *   if equal to NULL or "", label will be removed
+ *   for type SMACK_LABEL_TRANSMUTE valid values are NULL, "", "0" or "1"
+ * @param type label type to get
+ * @return 0 on success and negative value on failure.
+ */
+int smack_setlabel(const char *path, const char* label,
+               enum smack_label_type type);
+
+/*!
+ * Set SMACK label for file. If path points to a symbolic link, the
+ * function will set label of the link instead of file it refers to.
+ *
+ * @param path file system path
+ * @param label SMACK label to set
+ *   if equal to NULL or "", label will be removed
+ *   for type SMACK_LABEL_TRANSMUTE valid values are NULL, "", "0" or "1"
+ * @param type label type to get
+ * @return 0 on success and negative value on failure.
+ */
+int smack_lsetlabel(const char *path, const char* label,
+               enum smack_label_type type);
+
+/*!
+ * Get SMACK label from file descriptor.
+ *
+ * @param fd file descriptor
+ * @param label SMACK label to set
+ *   if equal to NULL or "", label will be removed
+ *   for type SMACK_LABEL_TRANSMUTE valid values are NULL, "", "0" or "1"
+ * @param type label type to get
+ * @return 0 on success and negative value on failure.
+ */
+int smack_fsetlabel(int fd, const char* label,
+               enum smack_label_type type);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _SYS_SMACK_H
diff --git a/src/strutils.c b/src/strutils.c
new file mode 100644 (file)
index 0000000..d56f70b
--- /dev/null
@@ -0,0 +1,64 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "sysdeps.h"
+#include "strutils.h"
+
+#ifndef PATH_MAX
+#define PATH_MAX 4096
+#endif
+
+
+size_t tokenize(const char *str, const char *delim, char *tokens[], size_t max_tokens ) {
+    int cnt = 0;
+
+    char tmp[PATH_MAX];
+
+    strncpy(tmp, str, PATH_MAX);
+    char *p = strtok(tmp, delim);
+    if (max_tokens < 1 || max_tokens > MAX_TOKENS) {
+        max_tokens = 1;
+    }
+
+    if (p != NULL) {
+        tokens[cnt++] = strdup(p);
+        while(cnt < max_tokens && p != NULL) {
+            p = strtok(NULL, delim);
+            if (p != NULL) {
+                tokens[cnt++] = strdup(p);
+            }
+        }
+    }
+    return cnt;
+}
+
+void free_strings(char **array, int n)
+{
+    int i;
+
+    for(i = 0; i < n; i++) {
+        if (array[i] != NULL) {
+            free(array[i]);
+        }
+    }
+}
+
+
+int read_line(const int fd, char* ptr, const unsigned int maxlen)
+{
+    unsigned int n = 0;
+    char c[2];
+    int rc;
+
+    while(n != maxlen) {
+        if((rc = sdb_read(fd, c, 1)) != 1)
+            return -1; // eof or read err
+
+        if(*c == '\n') {
+            ptr[n] = 0;
+            return n;
+        }
+        ptr[n++] = *c;
+    }
+    return -1; // no space
+}
diff --git a/src/strutils.h b/src/strutils.h
new file mode 100644 (file)
index 0000000..d31cb2a
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef _STRUTILS_H_
+#define _STRUTILS_H_
+
+#define MAX_TOKENS 30
+
+size_t tokenize(const char *str, const char *delim, char *tokens[], size_t max_tokens);
+void free_strings(char **array, int n);
+int read_line(const int fd, char* ptr, const unsigned int maxlen);
+
+#endif
+
index 2e23d6a0059904774465178d3ecaabf6caebb692..0b7022222f2cc7c8bd8721e0f856dc77e7a11e18 100644 (file)
@@ -428,6 +428,7 @@ static __inline__ int  sdb_socket_accept(int  serverfd, struct sockaddr*  addr,
     fd = accept(serverfd, addr, addrlen);
     if (fd >= 0) {
         if (close_on_exec(fd) < 0) {
+            sdb_close(fd);
             return -1;
         }
     }
index 4a5a71877b624738d62f5bd216d98695f7c2f7f0..cd72c0734bc3ba853ac24c32ebf859434dc73fa6 100644 (file)
@@ -599,7 +599,7 @@ static void register_device(const char *dev_name,
         n = ioctl(usb->desc, USBDEVFS_SETCONFIGURATION, &bConfigurationValue);
         if (n != 0) {
             D("[ usb set %d configuration failed %s fd = %d]\n", bConfigurationValue, usb->fname, usb->desc);
-            goto fail;
+            D("check kernel is supporting %dth configuration\n", bConfigurationValue);
         }
 
         n = ioctl(usb->desc, USBDEVFS_CLAIMINTERFACE, &interface);