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
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)/*
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
%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>
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;
" 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"
" 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"
"\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"
);
}
{
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;
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) {
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")) {
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 {
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);
}
}
if(!strcmp(argv[0], "version")) {
- version(stdout);
+ if (ttype == kTransportUsb || ttype == kTransportLocal) {
+ version_sdbd(ttype, serial);
+ } else {
+ version(stdout);
+ }
return 0;
}
}
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
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)
return err;
}
+
+void version_sdbd(transport_type ttype, char* serial) {
+ char* VERSION_QUERY ="shell:rpm -qa | grep sdbd";
+ send_shellcommand(ttype, serial, VERSION_QUERY);
+}
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;
}
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;
}
}
#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().
*/
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);
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;
}
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);
return -1;
// flush file system buffers due to N_SE-22305
sync();
+ } else {
+ D("sync error: %d!!!\n", fd);
+ return -1;
}
return 0;
//mode |= ((mode >> 3) & 0070);
//mode |= ((mode >> 3) & 0007);
-
ret = handle_send_file(s, path, mode, 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;
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;
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);
--- /dev/null
+#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
+}
--- /dev/null
+#ifndef _FILEUTILS_H_
+#define _FILEUTILS_H_
+
+int sdb_chmod(const char *path, mode_t mode, int recursive);
+#endif
+
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+/*
+ * 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;
+ }
+
+}
#define HAVE_PTHREADS
#include <stdio.h>
+#include "strutils.h"
#include "threads.h"
static mutex_t env_lock = MUTEX_INITIALIZER;
};
void property_save();
-int read_line(const int fd, char* ptr, const unsigned int maxlen);
static void property_init(void)
{
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_
#include <time.h>
#include <sys/time.h>
#include <signal.h>
+#include <grp.h>
#include "sysdeps.h"
#include "sdb.h"
int HOST = 0;
-
void handle_sig_term(int sig) {
#ifdef SDB_PIDPATH
if (access(SDB_PIDPATH, F_OK) == 0)
{ "jdwp", TRACE_JDWP },
{ "services", TRACE_SERVICES },
{ "properties", TRACE_PROPERTIES },
+ { "sdktools", TRACE_SDKTOOLS },
{ NULL, 0 }
};
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
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);
}
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);
#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;
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);
TRACE_SYSDEPS,
TRACE_JDWP,
TRACE_SERVICES,
- TRACE_PROPERTIES
+ TRACE_PROPERTIES,
+ TRACE_SDKTOOLS
} SdbTrace;
#if SDB_TRACE
--- /dev/null
+#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(®ex, pattern, REG_EXTENDED);
+ if(ret){ // not match
+ return 0;
+ }
+
+ // execute regular expression
+ ret = regexec(®ex, str, 0, NULL, 0);
+ if(!ret){
+ regfree(®ex);
+ return 1;
+ } else if( ret == REG_NOMATCH ){
+ //D("not valid application path\n");
+ } else{
+ //regerror(ret, ®ex, buf, sizeof(buf));
+ //D("regex match failed: %s\n", buf);
+ }
+ regfree(®ex);
+ 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;
+}
--- /dev/null
+#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
#include <unistd.h>
#include <string.h>
#include <errno.h>
+#include <grp.h>
#include "sysdeps.h"
#else
# include "android_reboot.h"
# include <sys/inotify.h>
+# include "sdktools.h"
#endif
typedef struct stinfo stinfo;
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];
int s[2];
if(sdb_socketpair(s)) {
- printf("cannot create service socket pair\n");
+ D("cannot create service socket pair\n");
return -1;
}
free(sti);
sdb_close(s[0]);
sdb_close(s[1]);
- printf("cannot create service thread\n");
+ D("cannot create service thread\n");
return -1;
}
}
#if !SDB_HOST
+
static int create_subprocess(const char *cmd, const char *arg0, const char *arg1, pid_t *pid)
{
#ifdef HAVE_WIN32_PROC
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;
}
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);
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)) {
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;
--- /dev/null
+/*
+ * 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
--- /dev/null
+#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
+}
--- /dev/null
+#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
+
fd = accept(serverfd, addr, addrlen);
if (fd >= 0) {
if (close_on_exec(fd) < 0) {
+ sdb_close(fd);
return -1;
}
}
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);