Author | Tokens | Token Proportion | Commits | Commit Proportion |
---|---|---|---|---|
Namjae Jeon | 1012 | 89.72% | 7 | 58.33% |
Atte Heikkilä | 80 | 7.09% | 3 | 25.00% |
Nandor Kracser | 35 | 3.10% | 1 | 8.33% |
Muhammad Usama Anjum | 1 | 0.09% | 1 | 8.33% |
Total | 1128 | 12 |
// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2018 Samsung Electronics Co., Ltd. */ #include <linux/list.h> #include <linux/jhash.h> #include <linux/slab.h> #include <linux/rwsem.h> #include <linux/parser.h> #include <linux/namei.h> #include <linux/sched.h> #include <linux/mm.h> #include "share_config.h" #include "user_config.h" #include "user_session.h" #include "../connection.h" #include "../transport_ipc.h" #include "../misc.h" #define SHARE_HASH_BITS 3 static DEFINE_HASHTABLE(shares_table, SHARE_HASH_BITS); static DECLARE_RWSEM(shares_table_lock); struct ksmbd_veto_pattern { char *pattern; struct list_head list; }; static unsigned int share_name_hash(const char *name) { return jhash(name, strlen(name), 0); } static void kill_share(struct ksmbd_share_config *share) { while (!list_empty(&share->veto_list)) { struct ksmbd_veto_pattern *p; p = list_entry(share->veto_list.next, struct ksmbd_veto_pattern, list); list_del(&p->list); kfree(p->pattern); kfree(p); } if (share->path) path_put(&share->vfs_path); kfree(share->name); kfree(share->path); kfree(share); } void ksmbd_share_config_del(struct ksmbd_share_config *share) { down_write(&shares_table_lock); hash_del(&share->hlist); up_write(&shares_table_lock); } void __ksmbd_share_config_put(struct ksmbd_share_config *share) { ksmbd_share_config_del(share); kill_share(share); } static struct ksmbd_share_config * __get_share_config(struct ksmbd_share_config *share) { if (!atomic_inc_not_zero(&share->refcount)) return NULL; return share; } static struct ksmbd_share_config *__share_lookup(const char *name) { struct ksmbd_share_config *share; unsigned int key = share_name_hash(name); hash_for_each_possible(shares_table, share, hlist, key) { if (!strcmp(name, share->name)) return share; } return NULL; } static int parse_veto_list(struct ksmbd_share_config *share, char *veto_list, int veto_list_sz) { int sz = 0; if (!veto_list_sz) return 0; while (veto_list_sz > 0) { struct ksmbd_veto_pattern *p; sz = strlen(veto_list); if (!sz) break; p = kzalloc(sizeof(struct ksmbd_veto_pattern), GFP_KERNEL); if (!p) return -ENOMEM; p->pattern = kstrdup(veto_list, GFP_KERNEL); if (!p->pattern) { kfree(p); return -ENOMEM; } list_add(&p->list, &share->veto_list); veto_list += sz + 1; veto_list_sz -= (sz + 1); } return 0; } static struct ksmbd_share_config *share_config_request(struct ksmbd_work *work, const char *name) { struct ksmbd_share_config_response *resp; struct ksmbd_share_config *share = NULL; struct ksmbd_share_config *lookup; struct unicode_map *um = work->conn->um; int ret; resp = ksmbd_ipc_share_config_request(name); if (!resp) return NULL; if (resp->flags == KSMBD_SHARE_FLAG_INVALID) goto out; if (*resp->share_name) { char *cf_resp_name; bool equal; cf_resp_name = ksmbd_casefold_sharename(um, resp->share_name); if (IS_ERR(cf_resp_name)) goto out; equal = !strcmp(cf_resp_name, name); kfree(cf_resp_name); if (!equal) goto out; } share = kzalloc(sizeof(struct ksmbd_share_config), GFP_KERNEL); if (!share) goto out; share->flags = resp->flags; atomic_set(&share->refcount, 1); INIT_LIST_HEAD(&share->veto_list); share->name = kstrdup(name, GFP_KERNEL); if (!test_share_config_flag(share, KSMBD_SHARE_FLAG_PIPE)) { int path_len = PATH_MAX; if (resp->payload_sz) path_len = resp->payload_sz - resp->veto_list_sz; share->path = kstrndup(ksmbd_share_config_path(resp), path_len, GFP_KERNEL); if (share->path) { share->path_sz = strlen(share->path); while (share->path_sz > 1 && share->path[share->path_sz - 1] == '/') share->path[--share->path_sz] = '\0'; } share->create_mask = resp->create_mask; share->directory_mask = resp->directory_mask; share->force_create_mode = resp->force_create_mode; share->force_directory_mode = resp->force_directory_mode; share->force_uid = resp->force_uid; share->force_gid = resp->force_gid; ret = parse_veto_list(share, KSMBD_SHARE_CONFIG_VETO_LIST(resp), resp->veto_list_sz); if (!ret && share->path) { if (__ksmbd_override_fsids(work, share)) { kill_share(share); share = NULL; goto out; } ret = kern_path(share->path, 0, &share->vfs_path); ksmbd_revert_fsids(work); if (ret) { ksmbd_debug(SMB, "failed to access '%s'\n", share->path); /* Avoid put_path() */ kfree(share->path); share->path = NULL; } } if (ret || !share->name) { kill_share(share); share = NULL; goto out; } } down_write(&shares_table_lock); lookup = __share_lookup(name); if (lookup) lookup = __get_share_config(lookup); if (!lookup) { hash_add(shares_table, &share->hlist, share_name_hash(name)); } else { kill_share(share); share = lookup; } up_write(&shares_table_lock); out: kvfree(resp); return share; } struct ksmbd_share_config *ksmbd_share_config_get(struct ksmbd_work *work, const char *name) { struct ksmbd_share_config *share; down_read(&shares_table_lock); share = __share_lookup(name); if (share) share = __get_share_config(share); up_read(&shares_table_lock); if (share) return share; return share_config_request(work, name); } bool ksmbd_share_veto_filename(struct ksmbd_share_config *share, const char *filename) { struct ksmbd_veto_pattern *p; list_for_each_entry(p, &share->veto_list, list) { if (match_wildcard(p->pattern, filename)) return true; } return false; }
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with Cregit http://github.com/cregit/cregit
Version 2.0-RC1