[CIFS] Migrate from prefixpath logic
[firefly-linux-kernel-4.4.55.git] / fs / cifs / link.c
1 /*
2  *   fs/cifs/link.c
3  *
4  *   Copyright (C) International Business Machines  Corp., 2002,2008
5  *   Author(s): Steve French (sfrench@us.ibm.com)
6  *
7  *   This library is free software; you can redistribute it and/or modify
8  *   it under the terms of the GNU Lesser General Public License as published
9  *   by the Free Software Foundation; either version 2.1 of the License, or
10  *   (at your option) any later version.
11  *
12  *   This library is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
15  *   the GNU Lesser General Public License for more details.
16  *
17  *   You should have received a copy of the GNU Lesser General Public License
18  *   along with this library; if not, write to the Free Software
19  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  */
21 #include <linux/fs.h>
22 #include <linux/stat.h>
23 #include <linux/slab.h>
24 #include <linux/namei.h>
25 #include "cifsfs.h"
26 #include "cifspdu.h"
27 #include "cifsglob.h"
28 #include "cifsproto.h"
29 #include "cifs_debug.h"
30 #include "cifs_fs_sb.h"
31
32 #define CIFS_MF_SYMLINK_LEN_OFFSET (4+1)
33 #define CIFS_MF_SYMLINK_MD5_OFFSET (CIFS_MF_SYMLINK_LEN_OFFSET+(4+1))
34 #define CIFS_MF_SYMLINK_LINK_OFFSET (CIFS_MF_SYMLINK_MD5_OFFSET+(32+1))
35 #define CIFS_MF_SYMLINK_LINK_MAXLEN (1024)
36 #define CIFS_MF_SYMLINK_FILE_SIZE \
37         (CIFS_MF_SYMLINK_LINK_OFFSET + CIFS_MF_SYMLINK_LINK_MAXLEN)
38
39 #define CIFS_MF_SYMLINK_LEN_FORMAT "XSym\n%04u\n"
40 #define CIFS_MF_SYMLINK_MD5_FORMAT \
41         "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n"
42 #define CIFS_MF_SYMLINK_MD5_ARGS(md5_hash) \
43         md5_hash[0],  md5_hash[1],  md5_hash[2],  md5_hash[3], \
44         md5_hash[4],  md5_hash[5],  md5_hash[6],  md5_hash[7], \
45         md5_hash[8],  md5_hash[9],  md5_hash[10], md5_hash[11],\
46         md5_hash[12], md5_hash[13], md5_hash[14], md5_hash[15]
47
48 static int
49 symlink_hash(unsigned int link_len, const char *link_str, u8 *md5_hash)
50 {
51         int rc;
52         unsigned int size;
53         struct crypto_shash *md5;
54         struct sdesc *sdescmd5;
55
56         md5 = crypto_alloc_shash("md5", 0, 0);
57         if (IS_ERR(md5)) {
58                 rc = PTR_ERR(md5);
59                 cERROR(1, "%s: Crypto md5 allocation error %d\n", __func__, rc);
60                 return rc;
61         }
62         size = sizeof(struct shash_desc) + crypto_shash_descsize(md5);
63         sdescmd5 = kmalloc(size, GFP_KERNEL);
64         if (!sdescmd5) {
65                 rc = -ENOMEM;
66                 cERROR(1, "%s: Memory allocation failure\n", __func__);
67                 goto symlink_hash_err;
68         }
69         sdescmd5->shash.tfm = md5;
70         sdescmd5->shash.flags = 0x0;
71
72         rc = crypto_shash_init(&sdescmd5->shash);
73         if (rc) {
74                 cERROR(1, "%s: Could not init md5 shash\n", __func__);
75                 goto symlink_hash_err;
76         }
77         crypto_shash_update(&sdescmd5->shash, link_str, link_len);
78         rc = crypto_shash_final(&sdescmd5->shash, md5_hash);
79
80 symlink_hash_err:
81         crypto_free_shash(md5);
82         kfree(sdescmd5);
83
84         return rc;
85 }
86
87 static int
88 CIFSParseMFSymlink(const u8 *buf,
89                    unsigned int buf_len,
90                    unsigned int *_link_len,
91                    char **_link_str)
92 {
93         int rc;
94         unsigned int link_len;
95         const char *md5_str1;
96         const char *link_str;
97         u8 md5_hash[16];
98         char md5_str2[34];
99
100         if (buf_len != CIFS_MF_SYMLINK_FILE_SIZE)
101                 return -EINVAL;
102
103         md5_str1 = (const char *)&buf[CIFS_MF_SYMLINK_MD5_OFFSET];
104         link_str = (const char *)&buf[CIFS_MF_SYMLINK_LINK_OFFSET];
105
106         rc = sscanf(buf, CIFS_MF_SYMLINK_LEN_FORMAT, &link_len);
107         if (rc != 1)
108                 return -EINVAL;
109
110         rc = symlink_hash(link_len, link_str, md5_hash);
111         if (rc) {
112                 cFYI(1, "%s: MD5 hash failure: %d\n", __func__, rc);
113                 return rc;
114         }
115
116         snprintf(md5_str2, sizeof(md5_str2),
117                  CIFS_MF_SYMLINK_MD5_FORMAT,
118                  CIFS_MF_SYMLINK_MD5_ARGS(md5_hash));
119
120         if (strncmp(md5_str1, md5_str2, 17) != 0)
121                 return -EINVAL;
122
123         if (_link_str) {
124                 *_link_str = kstrndup(link_str, link_len, GFP_KERNEL);
125                 if (!*_link_str)
126                         return -ENOMEM;
127         }
128
129         *_link_len = link_len;
130         return 0;
131 }
132
133 static int
134 CIFSFormatMFSymlink(u8 *buf, unsigned int buf_len, const char *link_str)
135 {
136         int rc;
137         unsigned int link_len;
138         unsigned int ofs;
139         u8 md5_hash[16];
140
141         if (buf_len != CIFS_MF_SYMLINK_FILE_SIZE)
142                 return -EINVAL;
143
144         link_len = strlen(link_str);
145
146         if (link_len > CIFS_MF_SYMLINK_LINK_MAXLEN)
147                 return -ENAMETOOLONG;
148
149         rc = symlink_hash(link_len, link_str, md5_hash);
150         if (rc) {
151                 cFYI(1, "%s: MD5 hash failure: %d\n", __func__, rc);
152                 return rc;
153         }
154
155         snprintf(buf, buf_len,
156                  CIFS_MF_SYMLINK_LEN_FORMAT CIFS_MF_SYMLINK_MD5_FORMAT,
157                  link_len,
158                  CIFS_MF_SYMLINK_MD5_ARGS(md5_hash));
159
160         ofs = CIFS_MF_SYMLINK_LINK_OFFSET;
161         memcpy(buf + ofs, link_str, link_len);
162
163         ofs += link_len;
164         if (ofs < CIFS_MF_SYMLINK_FILE_SIZE) {
165                 buf[ofs] = '\n';
166                 ofs++;
167         }
168
169         while (ofs < CIFS_MF_SYMLINK_FILE_SIZE) {
170                 buf[ofs] = ' ';
171                 ofs++;
172         }
173
174         return 0;
175 }
176
177 static int
178 CIFSCreateMFSymLink(const int xid, struct cifsTconInfo *tcon,
179                     const char *fromName, const char *toName,
180                     const struct nls_table *nls_codepage, int remap)
181 {
182         int rc;
183         int oplock = 0;
184         __u16 netfid = 0;
185         u8 *buf;
186         unsigned int bytes_written = 0;
187         struct cifs_io_parms io_parms;
188
189         buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL);
190         if (!buf)
191                 return -ENOMEM;
192
193         rc = CIFSFormatMFSymlink(buf, CIFS_MF_SYMLINK_FILE_SIZE, toName);
194         if (rc != 0) {
195                 kfree(buf);
196                 return rc;
197         }
198
199         rc = CIFSSMBOpen(xid, tcon, fromName, FILE_CREATE, GENERIC_WRITE,
200                          CREATE_NOT_DIR, &netfid, &oplock, NULL,
201                          nls_codepage, remap);
202         if (rc != 0) {
203                 kfree(buf);
204                 return rc;
205         }
206
207         io_parms.netfid = netfid;
208         io_parms.pid = current->tgid;
209         io_parms.tcon = tcon;
210         io_parms.offset = 0;
211         io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE;
212
213         rc = CIFSSMBWrite(xid, &io_parms, &bytes_written, buf, NULL, 0);
214         CIFSSMBClose(xid, tcon, netfid);
215         kfree(buf);
216         if (rc != 0)
217                 return rc;
218
219         if (bytes_written != CIFS_MF_SYMLINK_FILE_SIZE)
220                 return -EIO;
221
222         return 0;
223 }
224
225 static int
226 CIFSQueryMFSymLink(const int xid, struct cifsTconInfo *tcon,
227                    const unsigned char *searchName, char **symlinkinfo,
228                    const struct nls_table *nls_codepage, int remap)
229 {
230         int rc;
231         int oplock = 0;
232         __u16 netfid = 0;
233         u8 *buf;
234         char *pbuf;
235         unsigned int bytes_read = 0;
236         int buf_type = CIFS_NO_BUFFER;
237         unsigned int link_len = 0;
238         FILE_ALL_INFO file_info;
239
240         rc = CIFSSMBOpen(xid, tcon, searchName, FILE_OPEN, GENERIC_READ,
241                          CREATE_NOT_DIR, &netfid, &oplock, &file_info,
242                          nls_codepage, remap);
243         if (rc != 0)
244                 return rc;
245
246         if (file_info.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) {
247                 CIFSSMBClose(xid, tcon, netfid);
248                 /* it's not a symlink */
249                 return -EINVAL;
250         }
251
252         buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL);
253         if (!buf)
254                 return -ENOMEM;
255         pbuf = buf;
256
257         rc = CIFSSMBRead(xid, tcon, netfid,
258                          CIFS_MF_SYMLINK_FILE_SIZE /* length */,
259                          0 /* offset */,
260                          &bytes_read, &pbuf, &buf_type);
261         CIFSSMBClose(xid, tcon, netfid);
262         if (rc != 0) {
263                 kfree(buf);
264                 return rc;
265         }
266
267         rc = CIFSParseMFSymlink(buf, bytes_read, &link_len, symlinkinfo);
268         kfree(buf);
269         if (rc != 0)
270                 return rc;
271
272         return 0;
273 }
274
275 bool
276 CIFSCouldBeMFSymlink(const struct cifs_fattr *fattr)
277 {
278         if (!(fattr->cf_mode & S_IFREG))
279                 /* it's not a symlink */
280                 return false;
281
282         if (fattr->cf_eof != CIFS_MF_SYMLINK_FILE_SIZE)
283                 /* it's not a symlink */
284                 return false;
285
286         return true;
287 }
288
289 int
290 CIFSCheckMFSymlink(struct cifs_fattr *fattr,
291                    const unsigned char *path,
292                    struct cifs_sb_info *cifs_sb, int xid)
293 {
294         int rc;
295         int oplock = 0;
296         __u16 netfid = 0;
297         struct tcon_link *tlink;
298         struct cifsTconInfo *pTcon;
299         u8 *buf;
300         char *pbuf;
301         unsigned int bytes_read = 0;
302         int buf_type = CIFS_NO_BUFFER;
303         unsigned int link_len = 0;
304         FILE_ALL_INFO file_info;
305
306         if (!CIFSCouldBeMFSymlink(fattr))
307                 /* it's not a symlink */
308                 return 0;
309
310         tlink = cifs_sb_tlink(cifs_sb);
311         if (IS_ERR(tlink))
312                 return PTR_ERR(tlink);
313         pTcon = tlink_tcon(tlink);
314
315         rc = CIFSSMBOpen(xid, pTcon, path, FILE_OPEN, GENERIC_READ,
316                          CREATE_NOT_DIR, &netfid, &oplock, &file_info,
317                          cifs_sb->local_nls,
318                          cifs_sb->mnt_cifs_flags &
319                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
320         if (rc != 0)
321                 goto out;
322
323         if (file_info.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) {
324                 CIFSSMBClose(xid, pTcon, netfid);
325                 /* it's not a symlink */
326                 goto out;
327         }
328
329         buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL);
330         if (!buf) {
331                 rc = -ENOMEM;
332                 goto out;
333         }
334         pbuf = buf;
335
336         rc = CIFSSMBRead(xid, pTcon, netfid,
337                          CIFS_MF_SYMLINK_FILE_SIZE /* length */,
338                          0 /* offset */,
339                          &bytes_read, &pbuf, &buf_type);
340         CIFSSMBClose(xid, pTcon, netfid);
341         if (rc != 0) {
342                 kfree(buf);
343                 goto out;
344         }
345
346         rc = CIFSParseMFSymlink(buf, bytes_read, &link_len, NULL);
347         kfree(buf);
348         if (rc == -EINVAL) {
349                 /* it's not a symlink */
350                 rc = 0;
351                 goto out;
352         }
353
354         if (rc != 0)
355                 goto out;
356
357         /* it is a symlink */
358         fattr->cf_eof = link_len;
359         fattr->cf_mode &= ~S_IFMT;
360         fattr->cf_mode |= S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO;
361         fattr->cf_dtype = DT_LNK;
362 out:
363         cifs_put_tlink(tlink);
364         return rc;
365 }
366
367 int
368 cifs_hardlink(struct dentry *old_file, struct inode *inode,
369               struct dentry *direntry)
370 {
371         int rc = -EACCES;
372         int xid;
373         char *fromName = NULL;
374         char *toName = NULL;
375         struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
376         struct tcon_link *tlink;
377         struct cifsTconInfo *pTcon;
378         struct cifsInodeInfo *cifsInode;
379
380         tlink = cifs_sb_tlink(cifs_sb);
381         if (IS_ERR(tlink))
382                 return PTR_ERR(tlink);
383         pTcon = tlink_tcon(tlink);
384
385         xid = GetXid();
386
387         fromName = build_path_from_dentry(old_file);
388         toName = build_path_from_dentry(direntry);
389         if ((fromName == NULL) || (toName == NULL)) {
390                 rc = -ENOMEM;
391                 goto cifs_hl_exit;
392         }
393
394         if (pTcon->unix_ext)
395                 rc = CIFSUnixCreateHardLink(xid, pTcon, fromName, toName,
396                                             cifs_sb->local_nls,
397                                             cifs_sb->mnt_cifs_flags &
398                                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
399         else {
400                 rc = CIFSCreateHardLink(xid, pTcon, fromName, toName,
401                                         cifs_sb->local_nls,
402                                         cifs_sb->mnt_cifs_flags &
403                                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
404                 if ((rc == -EIO) || (rc == -EINVAL))
405                         rc = -EOPNOTSUPP;
406         }
407
408         d_drop(direntry);       /* force new lookup from server of target */
409
410         /* if source file is cached (oplocked) revalidate will not go to server
411            until the file is closed or oplock broken so update nlinks locally */
412         if (old_file->d_inode) {
413                 cifsInode = CIFS_I(old_file->d_inode);
414                 if (rc == 0) {
415                         old_file->d_inode->i_nlink++;
416 /* BB should we make this contingent on superblock flag NOATIME? */
417 /*                      old_file->d_inode->i_ctime = CURRENT_TIME;*/
418                         /* parent dir timestamps will update from srv
419                         within a second, would it really be worth it
420                         to set the parent dir cifs inode time to zero
421                         to force revalidate (faster) for it too? */
422                 }
423                 /* if not oplocked will force revalidate to get info
424                    on source file from srv */
425                 cifsInode->time = 0;
426
427                 /* Will update parent dir timestamps from srv within a second.
428                    Would it really be worth it to set the parent dir (cifs
429                    inode) time field to zero to force revalidate on parent
430                    directory faster ie
431                         CIFS_I(inode)->time = 0;  */
432         }
433
434 cifs_hl_exit:
435         kfree(fromName);
436         kfree(toName);
437         FreeXid(xid);
438         cifs_put_tlink(tlink);
439         return rc;
440 }
441
442 void *
443 cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
444 {
445         struct inode *inode = direntry->d_inode;
446         int rc = -ENOMEM;
447         int xid;
448         char *full_path = NULL;
449         char *target_path = NULL;
450         struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
451         struct tcon_link *tlink = NULL;
452         struct cifsTconInfo *tcon;
453
454         xid = GetXid();
455
456         tlink = cifs_sb_tlink(cifs_sb);
457         if (IS_ERR(tlink)) {
458                 rc = PTR_ERR(tlink);
459                 tlink = NULL;
460                 goto out;
461         }
462         tcon = tlink_tcon(tlink);
463
464         /*
465          * For now, we just handle symlinks with unix extensions enabled.
466          * Eventually we should handle NTFS reparse points, and MacOS
467          * symlink support. For instance...
468          *
469          * rc = CIFSSMBQueryReparseLinkInfo(...)
470          *
471          * For now, just return -EACCES when the server doesn't support posix
472          * extensions. Note that we still allow querying symlinks when posix
473          * extensions are manually disabled. We could disable these as well
474          * but there doesn't seem to be any harm in allowing the client to
475          * read them.
476          */
477         if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS)
478             && !(tcon->ses->capabilities & CAP_UNIX)) {
479                 rc = -EACCES;
480                 goto out;
481         }
482
483         full_path = build_path_from_dentry(direntry);
484         if (!full_path)
485                 goto out;
486
487         cFYI(1, "Full path: %s inode = 0x%p", full_path, inode);
488
489         rc = -EACCES;
490         /*
491          * First try Minshall+French Symlinks, if configured
492          * and fallback to UNIX Extensions Symlinks.
493          */
494         if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS)
495                 rc = CIFSQueryMFSymLink(xid, tcon, full_path, &target_path,
496                                         cifs_sb->local_nls,
497                                         cifs_sb->mnt_cifs_flags &
498                                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
499
500         if ((rc != 0) && (tcon->ses->capabilities & CAP_UNIX))
501                 rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, &target_path,
502                                              cifs_sb->local_nls);
503
504         kfree(full_path);
505 out:
506         if (rc != 0) {
507                 kfree(target_path);
508                 target_path = ERR_PTR(rc);
509         }
510
511         FreeXid(xid);
512         if (tlink)
513                 cifs_put_tlink(tlink);
514         nd_set_link(nd, target_path);
515         return NULL;
516 }
517
518 int
519 cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
520 {
521         int rc = -EOPNOTSUPP;
522         int xid;
523         struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
524         struct tcon_link *tlink;
525         struct cifsTconInfo *pTcon;
526         char *full_path = NULL;
527         struct inode *newinode = NULL;
528
529         xid = GetXid();
530
531         tlink = cifs_sb_tlink(cifs_sb);
532         if (IS_ERR(tlink)) {
533                 rc = PTR_ERR(tlink);
534                 goto symlink_exit;
535         }
536         pTcon = tlink_tcon(tlink);
537
538         full_path = build_path_from_dentry(direntry);
539         if (full_path == NULL) {
540                 rc = -ENOMEM;
541                 goto symlink_exit;
542         }
543
544         cFYI(1, "Full path: %s", full_path);
545         cFYI(1, "symname is %s", symname);
546
547         /* BB what if DFS and this volume is on different share? BB */
548         if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS)
549                 rc = CIFSCreateMFSymLink(xid, pTcon, full_path, symname,
550                                          cifs_sb->local_nls,
551                                          cifs_sb->mnt_cifs_flags &
552                                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
553         else if (pTcon->unix_ext)
554                 rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname,
555                                            cifs_sb->local_nls);
556         /* else
557            rc = CIFSCreateReparseSymLink(xid, pTcon, fromName, toName,
558                                         cifs_sb_target->local_nls); */
559
560         if (rc == 0) {
561                 if (pTcon->unix_ext)
562                         rc = cifs_get_inode_info_unix(&newinode, full_path,
563                                                       inode->i_sb, xid);
564                 else
565                         rc = cifs_get_inode_info(&newinode, full_path, NULL,
566                                                  inode->i_sb, xid, NULL);
567
568                 if (rc != 0) {
569                         cFYI(1, "Create symlink ok, getinodeinfo fail rc = %d",
570                               rc);
571                 } else {
572                         d_instantiate(direntry, newinode);
573                 }
574         }
575 symlink_exit:
576         kfree(full_path);
577         cifs_put_tlink(tlink);
578         FreeXid(xid);
579         return rc;
580 }
581
582 void cifs_put_link(struct dentry *direntry, struct nameidata *nd, void *cookie)
583 {
584         char *p = nd_get_link(nd);
585         if (!IS_ERR(p))
586                 kfree(p);
587 }