blob: 22eb96826513763c3853d89753fbc04d951f20ce [file] [log] [blame]
/*
* Copyright (c) 2015 Samsung Electronics Co., Ltd.
*
* Sensitive Data Protection
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <linux/debugfs.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/uaccess.h>
#include <linux/miscdevice.h>
#include <linux/slab.h>
#include <linux/ctype.h>
#include <sdp/dlp_ioctl.h>
#include <sdp/sdp_dlp.h>
#define DLP_DUMP_LIST 1 //TODO
static char *DLP_FILE_EXTENSIONS[] = {"xls", "xlsx", "doc", "docx", "ppt", "pptx", "pdf", "jpg", "jpeg", "zip", "mp4", "txt", "asd", "xlam", "htm", "html", "mht", "eml", "msg", "hwp", "gul", "rtf", "mysingle", "png", "gif"};
struct dlp_struct {
int user_id;
long time;
bool lock;
char* extensions;
struct list_head list;
struct mutex list_mutex;
};
struct dlp_struct dlp_info;
#if DLP_DUMP_LIST
static void dlp_dump_list(void) {
struct list_head *entry;
struct dlp_struct *tmp;
printk("============ debug ============\n");
mutex_lock(&dlp_info.list_mutex);
list_for_each(entry, &dlp_info.list) {
tmp = list_entry(entry, struct dlp_struct, list);
printk("DLP : user_id : %d\n", tmp->user_id);
printk("DLP : lock : %s\n", tmp->lock ? "true" : "false");
if (tmp->extensions) {
printk("DLP : extensions : %s\n", tmp->extensions);
} else {
printk("DLP : extensions : (empty)\n");
}
}
mutex_unlock(&dlp_info.list_mutex);
}
#endif
static struct dlp_struct *dlp_find_list(int user_id) {
struct list_head *entry;
struct dlp_struct *tmp;
mutex_lock(&dlp_info.list_mutex);
printk("DLP: user_id %d\n", user_id);
list_for_each(entry, &dlp_info.list) {
tmp = list_entry(entry, struct dlp_struct, list);
printk("DLP: tmp->user_id %d\n", tmp->user_id);
if(tmp->user_id == user_id) {
printk("DLP: found user_id %d\n", user_id); // TODO : deleted
mutex_unlock(&dlp_info.list_mutex);
return tmp;
}
}
mutex_unlock(&dlp_info.list_mutex);
return NULL;
}
bool dlp_is_locked(int user_id) {
struct dlp_struct *tmp;
tmp = dlp_find_list(user_id);
if(tmp){
return tmp->lock;
}
else {
return false;
}
}
static struct dlp_struct *dlp_add_info(int user_id){
struct dlp_struct *new_item;
new_item = kmalloc(sizeof(struct dlp_struct), GFP_KERNEL);
if(new_item == NULL) {
printk("DLP: can't alloc memory for dlp_info\n");
return NULL;
}
new_item->user_id = user_id;
new_item->lock = false;
new_item->extensions = NULL;
mutex_init(&new_item->list_mutex);
INIT_LIST_HEAD(&new_item->list);
mutex_lock(&dlp_info.list_mutex);
list_add_tail(&new_item->list, &dlp_info.list);
mutex_unlock(&dlp_info.list_mutex);
return new_item;
}
static int dlp_lock_setting(void __user *argp, bool lock) {
int ret = 0;
struct dlp_struct *tmp = NULL;
struct _dlp_lock_set dlp_lock_set;
ret = copy_from_user(&dlp_lock_set, (void __user *)argp, sizeof(dlp_lock_set));
if(ret) {
printk("DLP : fail to copy_from_user : dlp_lock_setting\n");
return -EFAULT;
}
tmp = dlp_find_list(dlp_lock_set.user_id);
if(tmp == NULL){
tmp = dlp_add_info(dlp_lock_set.user_id);
if(tmp == NULL){
return -EFAULT;
}
}
mutex_lock(&dlp_info.list_mutex);
tmp->lock = lock;
mutex_unlock(&dlp_info.list_mutex);
return 0;
};
static int dlp_extension_setting(void __user *argp) {
int ret = 0;
struct dlp_struct *tmp = NULL;
struct _dlp_extension_set dlp_ext_set;
ret = copy_from_user(&dlp_ext_set, (void __user *)argp, sizeof(dlp_ext_set));
if(ret) {
printk("DLP : fail to copy_from_user : dlp_extension_setting\n");
return -EFAULT;
}
printk("DLP: dlp_extension_setting called with user_id %d\n", dlp_ext_set.user_id);
tmp = dlp_find_list(dlp_ext_set.user_id);
if(tmp == NULL){
tmp = dlp_add_info(dlp_ext_set.user_id);
if(tmp == NULL){
return -EFAULT;
}
}
/* Delete old extensions and create new */
mutex_lock(&dlp_info.list_mutex);
if(tmp->extensions) {
kfree(tmp->extensions);
tmp->extensions = NULL;
}
if(strlen(dlp_ext_set.extensions)) {
tmp->extensions = kmalloc(strlen(dlp_ext_set.extensions)+1, GFP_KERNEL);
if (!tmp->extensions) {
mutex_unlock(&dlp_info.list_mutex);
return -EFAULT;
}
} else {
mutex_unlock(&dlp_info.list_mutex);
return 0;
}
strcpy(tmp->extensions, dlp_ext_set.extensions);
mutex_unlock(&dlp_info.list_mutex);
return 0;
}
static long dlp_ioctl(struct file *file, unsigned cmd,
unsigned long arg) {
int ret = 0;
void __user *argp = (void __user *) arg;
switch (cmd) {
case DLP_LOCK_ENABLE: {
printk("DLP: DLP_LOCK_ENABLE\n");
ret = dlp_lock_setting(argp, true);
break;
}
case DLP_LOCK_DISABLE: {
printk("DLP: DLP_LOCK_DISABLE\n");
ret = dlp_lock_setting(argp, false);
break;
}
case DLP_EXTENSION_SET: {
printk("DLP: DLP_EXTENSION_SET\n");
ret = dlp_extension_setting(argp);
break;
}
default:
pr_err("DLP : Invalid IOCTL: %d\n", cmd);
return -EINVAL;
}
#if DLP_DUMP_LIST
dlp_dump_list();
#endif
return ret;
}
int dlp_isInterestedFile(int user_id, const char *filename){
int i, j;
char *ext, *ret;
char lower[256];
struct dlp_struct *item = NULL;
ext = strrchr(filename, '.');
printk("DLP: dlp_isInterestedFile : %s\n", filename);
if(ext == NULL){
printk("DLP: Ext not found\n");
return -1;
}else{
ext++;
strncpy(lower, ext, sizeof(lower)-1);
lower[sizeof(lower)-1] = '\0';
for (j=0; j < strlen(lower); j++) {
lower[j] = tolower(lower[j]);
}
printk("DLP: extension : %s\n", lower);
}
item = dlp_find_list(user_id);
if(item == NULL || item->extensions == NULL){
//extensions for DLP is not set ...
// check if the extension is matching with default extensions
printk("DLP: extension set for DLP is not set\n");
for(i=(sizeof(DLP_FILE_EXTENSIONS)/sizeof(char*) -1); i>=0; i--){
if(strcmp(DLP_FILE_EXTENSIONS[i], lower)==0){
return 0;
}
}
printk("DLP: extension not matching with default return -1\n");
return -1;
}
printk("DLP: extension = %s\n", item->extensions);
strcat(lower, ","); // add comma, so that we compare each ext fully (doc vs. docx)
mutex_lock(&dlp_info.list_mutex);
ret = strstr(item->extensions, lower);
mutex_unlock(&dlp_info.list_mutex);
if (ret) {
return 0;
} else {
return -1;
}
}
const struct file_operations dlp_fops_evt = {
.owner = THIS_MODULE,
.unlocked_ioctl = dlp_ioctl,
.compat_ioctl = dlp_ioctl,
};
static struct miscdevice dlp_misc_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = "sdp_dlp",
.fops = &dlp_fops_evt,
};
static int __init dlp_ioctl_init(void) {
int ret;
ret = misc_register(&dlp_misc_dev);
if (unlikely(ret)) {
printk("DLP: failed to register sdp_dlp device!\n");
return ret;
}
INIT_LIST_HEAD(&dlp_info.list);
mutex_init(&dlp_info.list_mutex);
printk("DLP: dlp_ioctl initialized\n");
return 0;
}
static void __exit dlp_ioctl_exit(void) {
misc_deregister(&dlp_misc_dev);
printk("DLP: dlp_ioctl mics_deregister\n");
}
module_init(dlp_ioctl_init);
module_exit(dlp_ioctl_exit);