From d645a7a947f51f5dfc0e769fe74031e1350d53e4 Mon Sep 17 00:00:00 2001 From: "yoonki.park" Date: Thu, 4 Apr 2013 01:48:06 +0900 Subject: [PATCH] version up to 2.1.0 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 --- Makefile | 11 +- packaging/sdbd.spec | 9 +- src/commandline.c | 94 ++++-- src/file_sync_client.c | 5 +- src/file_sync_service.c | 74 ++++- src/file_sync_service.h | 1 + src/fileutils.c | 49 +++ src/fileutils.h | 6 + src/init.c | 187 +++++++++++ src/libsmack.c | 811 ++++++++++++++++++++++++++++++++++++++++++++++++ src/properties.c | 21 +- src/sdb.c | 142 +++++---- src/sdb.h | 23 +- src/sdktools.c | 412 ++++++++++++++++++++++++ src/sdktools.h | 49 +++ src/services.c | 76 ++++- src/smack.h | 287 +++++++++++++++++ src/strutils.c | 64 ++++ src/strutils.h | 11 + src/sysdeps.h | 1 + src/usb_linux.c | 2 +- 21 files changed, 2183 insertions(+), 152 deletions(-) create mode 100644 src/fileutils.c create mode 100644 src/fileutils.h create mode 100644 src/init.c create mode 100644 src/libsmack.c create mode 100644 src/sdktools.c create mode 100644 src/sdktools.h create mode 100644 src/smack.h create mode 100644 src/strutils.c create mode 100644 src/strutils.h diff --git a/Makefile b/Makefile index 60389b8..0286362 100644 --- 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)/* diff --git a/packaging/sdbd.spec b/packaging/sdbd.spec index 2ba0402..81b1de4 100644 --- a/packaging/sdbd.spec +++ b/packaging/sdbd.spec @@ -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 diff --git a/src/commandline.c b/src/commandline.c index 9c2885a..730509b 100644 --- a/src/commandline.c +++ b/src/commandline.c @@ -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] [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 - 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 - direct command to the USB device or emulator with\n" " the given serial number.\n" " devices - list all connected devices\n" " connect [:] - 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 [-with-utf8]\n" + " sdb push [--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 [] - copy file/dir from device\n" " sdb shell - run remote shell interactively\n" " sdb shell - run remote shell \n" - " sdb dlog [ ] - view device log\n" - " sdb install - push tpk package file and install it\n" + " sdb dlog [] - view device log\n" + " sdb install - push tpk package file and install it\n" " sdb uninstall - uninstall this app from the device\n" " sdb forward - 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: \n" + " sdb get-state - print: offline | bootloader | device\n" + " sdb get-serialno - print: \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 - 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 - 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); +} diff --git a/src/file_sync_client.c b/src/file_sync_client.c index 95e8632..8561250 100644 --- a/src/file_sync_client.c +++ b/src/file_sync_client.c @@ -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; } } diff --git a/src/file_sync_service.c b/src/file_sync_service.c index 75f2840..7437e9b 100644 --- a/src/file_sync_service.c +++ b/src/file_sync_service.c @@ -22,7 +22,7 @@ #include #include #include - +#include #include #include "sysdeps.h" @@ -31,6 +31,20 @@ #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(®ex, sdk_sync_permit_rule[i].regx, REG_EXTENDED); + if(ret){ + return 0; + } + // execute regular expression + ret = regexec(®ex, path, 0, NULL, 0); + if(!ret){ + regfree(®ex); + 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, ®ex, buf, sizeof(buf)); + D("regex match failed(%s): %s\n",sdk_sync_permit_rule[i].name, buf); + } + } + regfree(®ex); 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; diff --git a/src/file_sync_service.h b/src/file_sync_service.h index 84f06bb..68059da 100644 --- a/src/file_sync_service.h +++ b/src/file_sync_service.h @@ -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 index 0000000..bb5071b --- /dev/null +++ b/src/fileutils.c @@ -0,0 +1,49 @@ +#include +#include +#include +#include +#include +#include + +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 index 0000000..4debc92 --- /dev/null +++ b/src/fileutils.h @@ -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 index 0000000..bec59f2 --- /dev/null +++ b/src/init.c @@ -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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * * 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 index 0000000..03fa8eb --- /dev/null +++ b/src/libsmack.c @@ -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 + * Brian McGillion + * Passion Zhao + * Rafal Krypa + */ + +#include "smack.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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; + } + +} diff --git a/src/properties.c b/src/properties.c index 275a1a4..c187d30 100644 --- a/src/properties.c +++ b/src/properties.c @@ -35,6 +35,7 @@ #define HAVE_PTHREADS #include +#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_ diff --git a/src/sdb.c b/src/sdb.c index 49fd90e..fea30f4 100644 --- a/src/sdb.c +++ b/src/sdb.c @@ -25,6 +25,7 @@ #include #include #include +#include #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); diff --git a/src/sdb.h b/src/sdb.h index a6a052d..41ce734 100644 --- 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 index 0000000..16e40f4 --- /dev/null +++ b/src/sdktools.c @@ -0,0 +1,412 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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) 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 index 0000000..34f2ecb --- /dev/null +++ b/src/sdktools.h @@ -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 diff --git a/src/services.c b/src/services.c index f31bf83..2ecaacc 100644 --- a/src/services.c +++ b/src/services.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "sysdeps.h" @@ -35,6 +36,7 @@ #else # include "android_reboot.h" # include +# 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 index 0000000..50504a5 --- /dev/null +++ b/src/smack.h @@ -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 + * Rafal Krypa + */ + +/*! + * Smack user space library + */ + +#ifndef _SYS_SMACK_H +#define _SYS_SMACK_H + +#include + +/*! + * 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 index 0000000..d56f70b --- /dev/null +++ b/src/strutils.c @@ -0,0 +1,64 @@ +#include +#include +#include +#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 index 0000000..d31cb2a --- /dev/null +++ b/src/strutils.h @@ -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 + diff --git a/src/sysdeps.h b/src/sysdeps.h index 2e23d6a..0b70222 100644 --- a/src/sysdeps.h +++ b/src/sysdeps.h @@ -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; } } diff --git a/src/usb_linux.c b/src/usb_linux.c index 4a5a718..cd72c07 100644 --- a/src/usb_linux.c +++ b/src/usb_linux.c @@ -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); -- 2.7.4