/* * 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 #include #include #include #include #include #include #include #include #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);