0001
0002
0003
0004
0005
0006 #include <linux/list.h>
0007 #include <linux/jhash.h>
0008 #include <linux/slab.h>
0009 #include <linux/rwsem.h>
0010 #include <linux/parser.h>
0011 #include <linux/namei.h>
0012 #include <linux/sched.h>
0013 #include <linux/mm.h>
0014
0015 #include "share_config.h"
0016 #include "user_config.h"
0017 #include "user_session.h"
0018 #include "../transport_ipc.h"
0019
0020 #define SHARE_HASH_BITS 3
0021 static DEFINE_HASHTABLE(shares_table, SHARE_HASH_BITS);
0022 static DECLARE_RWSEM(shares_table_lock);
0023
0024 struct ksmbd_veto_pattern {
0025 char *pattern;
0026 struct list_head list;
0027 };
0028
0029 static unsigned int share_name_hash(char *name)
0030 {
0031 return jhash(name, strlen(name), 0);
0032 }
0033
0034 static void kill_share(struct ksmbd_share_config *share)
0035 {
0036 while (!list_empty(&share->veto_list)) {
0037 struct ksmbd_veto_pattern *p;
0038
0039 p = list_entry(share->veto_list.next,
0040 struct ksmbd_veto_pattern,
0041 list);
0042 list_del(&p->list);
0043 kfree(p->pattern);
0044 kfree(p);
0045 }
0046
0047 if (share->path)
0048 path_put(&share->vfs_path);
0049 kfree(share->name);
0050 kfree(share->path);
0051 kfree(share);
0052 }
0053
0054 void ksmbd_share_config_del(struct ksmbd_share_config *share)
0055 {
0056 down_write(&shares_table_lock);
0057 hash_del(&share->hlist);
0058 up_write(&shares_table_lock);
0059 }
0060
0061 void __ksmbd_share_config_put(struct ksmbd_share_config *share)
0062 {
0063 ksmbd_share_config_del(share);
0064 kill_share(share);
0065 }
0066
0067 static struct ksmbd_share_config *
0068 __get_share_config(struct ksmbd_share_config *share)
0069 {
0070 if (!atomic_inc_not_zero(&share->refcount))
0071 return NULL;
0072 return share;
0073 }
0074
0075 static struct ksmbd_share_config *__share_lookup(char *name)
0076 {
0077 struct ksmbd_share_config *share;
0078 unsigned int key = share_name_hash(name);
0079
0080 hash_for_each_possible(shares_table, share, hlist, key) {
0081 if (!strcmp(name, share->name))
0082 return share;
0083 }
0084 return NULL;
0085 }
0086
0087 static int parse_veto_list(struct ksmbd_share_config *share,
0088 char *veto_list,
0089 int veto_list_sz)
0090 {
0091 int sz = 0;
0092
0093 if (!veto_list_sz)
0094 return 0;
0095
0096 while (veto_list_sz > 0) {
0097 struct ksmbd_veto_pattern *p;
0098
0099 sz = strlen(veto_list);
0100 if (!sz)
0101 break;
0102
0103 p = kzalloc(sizeof(struct ksmbd_veto_pattern), GFP_KERNEL);
0104 if (!p)
0105 return -ENOMEM;
0106
0107 p->pattern = kstrdup(veto_list, GFP_KERNEL);
0108 if (!p->pattern) {
0109 kfree(p);
0110 return -ENOMEM;
0111 }
0112
0113 list_add(&p->list, &share->veto_list);
0114
0115 veto_list += sz + 1;
0116 veto_list_sz -= (sz + 1);
0117 }
0118
0119 return 0;
0120 }
0121
0122 static struct ksmbd_share_config *share_config_request(char *name)
0123 {
0124 struct ksmbd_share_config_response *resp;
0125 struct ksmbd_share_config *share = NULL;
0126 struct ksmbd_share_config *lookup;
0127 int ret;
0128
0129 resp = ksmbd_ipc_share_config_request(name);
0130 if (!resp)
0131 return NULL;
0132
0133 if (resp->flags == KSMBD_SHARE_FLAG_INVALID)
0134 goto out;
0135
0136 share = kzalloc(sizeof(struct ksmbd_share_config), GFP_KERNEL);
0137 if (!share)
0138 goto out;
0139
0140 share->flags = resp->flags;
0141 atomic_set(&share->refcount, 1);
0142 INIT_LIST_HEAD(&share->veto_list);
0143 share->name = kstrdup(name, GFP_KERNEL);
0144
0145 if (!test_share_config_flag(share, KSMBD_SHARE_FLAG_PIPE)) {
0146 share->path = kstrdup(ksmbd_share_config_path(resp),
0147 GFP_KERNEL);
0148 if (share->path)
0149 share->path_sz = strlen(share->path);
0150 share->create_mask = resp->create_mask;
0151 share->directory_mask = resp->directory_mask;
0152 share->force_create_mode = resp->force_create_mode;
0153 share->force_directory_mode = resp->force_directory_mode;
0154 share->force_uid = resp->force_uid;
0155 share->force_gid = resp->force_gid;
0156 ret = parse_veto_list(share,
0157 KSMBD_SHARE_CONFIG_VETO_LIST(resp),
0158 resp->veto_list_sz);
0159 if (!ret && share->path) {
0160 ret = kern_path(share->path, 0, &share->vfs_path);
0161 if (ret) {
0162 ksmbd_debug(SMB, "failed to access '%s'\n",
0163 share->path);
0164
0165 kfree(share->path);
0166 share->path = NULL;
0167 }
0168 }
0169 if (ret || !share->name) {
0170 kill_share(share);
0171 share = NULL;
0172 goto out;
0173 }
0174 }
0175
0176 down_write(&shares_table_lock);
0177 lookup = __share_lookup(name);
0178 if (lookup)
0179 lookup = __get_share_config(lookup);
0180 if (!lookup) {
0181 hash_add(shares_table, &share->hlist, share_name_hash(name));
0182 } else {
0183 kill_share(share);
0184 share = lookup;
0185 }
0186 up_write(&shares_table_lock);
0187
0188 out:
0189 kvfree(resp);
0190 return share;
0191 }
0192
0193 static void strtolower(char *share_name)
0194 {
0195 while (*share_name) {
0196 *share_name = tolower(*share_name);
0197 share_name++;
0198 }
0199 }
0200
0201 struct ksmbd_share_config *ksmbd_share_config_get(char *name)
0202 {
0203 struct ksmbd_share_config *share;
0204
0205 strtolower(name);
0206
0207 down_read(&shares_table_lock);
0208 share = __share_lookup(name);
0209 if (share)
0210 share = __get_share_config(share);
0211 up_read(&shares_table_lock);
0212
0213 if (share)
0214 return share;
0215 return share_config_request(name);
0216 }
0217
0218 bool ksmbd_share_veto_filename(struct ksmbd_share_config *share,
0219 const char *filename)
0220 {
0221 struct ksmbd_veto_pattern *p;
0222
0223 list_for_each_entry(p, &share->veto_list, list) {
0224 if (match_wildcard(p->pattern, filename))
0225 return true;
0226 }
0227 return false;
0228 }