Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *   Copyright (C) 2018 Samsung Electronics Co., Ltd.
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                 /* Avoid put_path() */
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 }