0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/dcache.h>
0013 #include <linux/mount.h>
0014 #include <linux/namei.h>
0015 #include <linux/slab.h>
0016 #include <linux/vfs.h>
0017 #include <linux/fs.h>
0018 #include <linux/inet.h>
0019 #include "cifsglob.h"
0020 #include "cifsproto.h"
0021 #include "cifsfs.h"
0022 #include "dns_resolve.h"
0023 #include "cifs_debug.h"
0024 #include "cifs_unicode.h"
0025 #include "dfs_cache.h"
0026 #include "fs_context.h"
0027
0028 static LIST_HEAD(cifs_dfs_automount_list);
0029
0030 static void cifs_dfs_expire_automounts(struct work_struct *work);
0031 static DECLARE_DELAYED_WORK(cifs_dfs_automount_task,
0032 cifs_dfs_expire_automounts);
0033 static int cifs_dfs_mountpoint_expiry_timeout = 500 * HZ;
0034
0035 static void cifs_dfs_expire_automounts(struct work_struct *work)
0036 {
0037 struct list_head *list = &cifs_dfs_automount_list;
0038
0039 mark_mounts_for_expiry(list);
0040 if (!list_empty(list))
0041 schedule_delayed_work(&cifs_dfs_automount_task,
0042 cifs_dfs_mountpoint_expiry_timeout);
0043 }
0044
0045 void cifs_dfs_release_automount_timer(void)
0046 {
0047 BUG_ON(!list_empty(&cifs_dfs_automount_list));
0048 cancel_delayed_work_sync(&cifs_dfs_automount_task);
0049 }
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063 static char *
0064 cifs_build_devname(char *nodename, const char *prepath)
0065 {
0066 size_t pplen;
0067 size_t unclen;
0068 char *dev;
0069 char *pos;
0070
0071
0072 nodename += strspn(nodename, "\\");
0073 if (!*nodename)
0074 return ERR_PTR(-EINVAL);
0075
0076
0077 unclen = strlen(nodename);
0078 pos = nodename + unclen - 1;
0079
0080
0081 while (*pos == '\\') {
0082 --pos;
0083 --unclen;
0084 }
0085
0086
0087
0088
0089
0090
0091 pplen = prepath ? strlen(prepath) : 0;
0092 dev = kmalloc(2 + unclen + 1 + pplen + 1, GFP_KERNEL);
0093 if (!dev)
0094 return ERR_PTR(-ENOMEM);
0095
0096 pos = dev;
0097
0098 *pos = '/';
0099 ++pos;
0100 *pos = '/';
0101 ++pos;
0102
0103
0104 memcpy(pos, nodename, unclen);
0105 pos += unclen;
0106
0107
0108 if (pplen) {
0109 *pos = '/';
0110 ++pos;
0111 memcpy(pos, prepath, pplen);
0112 pos += pplen;
0113 }
0114
0115
0116 *pos = '\0';
0117
0118 convert_delimiter(dev, '/');
0119 return dev;
0120 }
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135 char *cifs_compose_mount_options(const char *sb_mountdata,
0136 const char *fullpath,
0137 const struct dfs_info3_param *ref,
0138 char **devname)
0139 {
0140 int rc;
0141 char *name;
0142 char *mountdata = NULL;
0143 const char *prepath = NULL;
0144 int md_len;
0145 char *tkn_e;
0146 char *srvIP = NULL;
0147 char sep = ',';
0148 int off, noff;
0149
0150 if (sb_mountdata == NULL)
0151 return ERR_PTR(-EINVAL);
0152
0153 if (ref) {
0154 if (WARN_ON_ONCE(!ref->node_name || ref->path_consumed < 0))
0155 return ERR_PTR(-EINVAL);
0156
0157 if (strlen(fullpath) - ref->path_consumed) {
0158 prepath = fullpath + ref->path_consumed;
0159
0160 if (*prepath == '/' || *prepath == '\\')
0161 prepath++;
0162 }
0163
0164 name = cifs_build_devname(ref->node_name, prepath);
0165 if (IS_ERR(name)) {
0166 rc = PTR_ERR(name);
0167 name = NULL;
0168 goto compose_mount_options_err;
0169 }
0170 } else {
0171 name = cifs_build_devname((char *)fullpath, NULL);
0172 if (IS_ERR(name)) {
0173 rc = PTR_ERR(name);
0174 name = NULL;
0175 goto compose_mount_options_err;
0176 }
0177 }
0178
0179 rc = dns_resolve_server_name_to_ip(name, &srvIP, NULL);
0180 if (rc < 0) {
0181 cifs_dbg(FYI, "%s: Failed to resolve server part of %s to IP: %d\n",
0182 __func__, name, rc);
0183 goto compose_mount_options_err;
0184 }
0185
0186
0187
0188
0189
0190
0191
0192 md_len = strlen(sb_mountdata) + INET6_ADDRSTRLEN;
0193 mountdata = kzalloc(md_len + sizeof("ip=") + 1, GFP_KERNEL);
0194 if (mountdata == NULL) {
0195 rc = -ENOMEM;
0196 goto compose_mount_options_err;
0197 }
0198
0199
0200 off = 0;
0201 if (strncmp(sb_mountdata, "sep=", 4) == 0) {
0202 sep = sb_mountdata[4];
0203 strncpy(mountdata, sb_mountdata, 5);
0204 off += 5;
0205 }
0206
0207 do {
0208 tkn_e = strchr(sb_mountdata + off, sep);
0209 if (tkn_e == NULL)
0210 noff = strlen(sb_mountdata + off);
0211 else
0212 noff = tkn_e - (sb_mountdata + off) + 1;
0213
0214 if (strncasecmp(sb_mountdata + off, "cruid=", 6) == 0) {
0215 off += noff;
0216 continue;
0217 }
0218 if (strncasecmp(sb_mountdata + off, "unc=", 4) == 0) {
0219 off += noff;
0220 continue;
0221 }
0222 if (strncasecmp(sb_mountdata + off, "ip=", 3) == 0) {
0223 off += noff;
0224 continue;
0225 }
0226 if (strncasecmp(sb_mountdata + off, "prefixpath=", 11) == 0) {
0227 off += noff;
0228 continue;
0229 }
0230 strncat(mountdata, sb_mountdata + off, noff);
0231 off += noff;
0232 } while (tkn_e);
0233 strcat(mountdata, sb_mountdata + off);
0234 mountdata[md_len] = '\0';
0235
0236
0237 if (mountdata[strlen(mountdata) - 1] != sep)
0238 strncat(mountdata, &sep, 1);
0239 strcat(mountdata, "ip=");
0240 strcat(mountdata, srvIP);
0241
0242 if (devname)
0243 *devname = name;
0244 else
0245 kfree(name);
0246
0247
0248
0249
0250 compose_mount_options_out:
0251 kfree(srvIP);
0252 return mountdata;
0253
0254 compose_mount_options_err:
0255 kfree(mountdata);
0256 mountdata = ERR_PTR(rc);
0257 kfree(name);
0258 goto compose_mount_options_out;
0259 }
0260
0261
0262
0263
0264
0265
0266
0267
0268
0269
0270
0271
0272 static struct vfsmount *cifs_dfs_do_mount(struct dentry *mntpt,
0273 struct cifs_sb_info *cifs_sb,
0274 const char *fullpath)
0275 {
0276 struct vfsmount *mnt;
0277 char *mountdata;
0278 char *devname;
0279
0280 devname = kstrdup(fullpath, GFP_KERNEL);
0281 if (!devname)
0282 return ERR_PTR(-ENOMEM);
0283
0284 convert_delimiter(devname, '/');
0285
0286
0287
0288
0289
0290
0291 mountdata = cifs_compose_mount_options(cifs_sb->ctx->mount_options,
0292 fullpath + 1, NULL, NULL);
0293 if (IS_ERR(mountdata)) {
0294 kfree(devname);
0295 return (struct vfsmount *)mountdata;
0296 }
0297
0298 mnt = vfs_submount(mntpt, &cifs_fs_type, devname, mountdata);
0299 kfree(mountdata);
0300 kfree(devname);
0301 return mnt;
0302 }
0303
0304
0305
0306
0307 static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
0308 {
0309 struct cifs_sb_info *cifs_sb;
0310 void *page;
0311 char *full_path;
0312 struct vfsmount *mnt;
0313
0314 cifs_dbg(FYI, "in %s\n", __func__);
0315 BUG_ON(IS_ROOT(mntpt));
0316
0317
0318
0319
0320
0321
0322
0323 cifs_sb = CIFS_SB(mntpt->d_sb);
0324 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS) {
0325 mnt = ERR_PTR(-EREMOTE);
0326 goto cdda_exit;
0327 }
0328
0329 page = alloc_dentry_path();
0330
0331 full_path = build_path_from_dentry_optional_prefix(mntpt, page, true);
0332 if (IS_ERR(full_path)) {
0333 mnt = ERR_CAST(full_path);
0334 goto free_full_path;
0335 }
0336
0337 convert_delimiter(full_path, '\\');
0338 cifs_dbg(FYI, "%s: full_path: %s\n", __func__, full_path);
0339
0340 mnt = cifs_dfs_do_mount(mntpt, cifs_sb, full_path);
0341 cifs_dbg(FYI, "%s: cifs_dfs_do_mount:%s , mnt:%p\n", __func__, full_path + 1, mnt);
0342
0343 free_full_path:
0344 free_dentry_path(page);
0345 cdda_exit:
0346 cifs_dbg(FYI, "leaving %s\n" , __func__);
0347 return mnt;
0348 }
0349
0350
0351
0352
0353 struct vfsmount *cifs_dfs_d_automount(struct path *path)
0354 {
0355 struct vfsmount *newmnt;
0356
0357 cifs_dbg(FYI, "in %s\n", __func__);
0358
0359 newmnt = cifs_dfs_do_automount(path->dentry);
0360 if (IS_ERR(newmnt)) {
0361 cifs_dbg(FYI, "leaving %s [automount failed]\n" , __func__);
0362 return newmnt;
0363 }
0364
0365 mntget(newmnt);
0366 mnt_set_expiry(newmnt, &cifs_dfs_automount_list);
0367 schedule_delayed_work(&cifs_dfs_automount_task,
0368 cifs_dfs_mountpoint_expiry_timeout);
0369 cifs_dbg(FYI, "leaving %s [ok]\n" , __func__);
0370 return newmnt;
0371 }
0372
0373 const struct inode_operations cifs_dfs_referral_inode_operations = {
0374 };