various endian fixes to cifs
[linux-3.10.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
188         buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL);
189         if (!buf)
190                 return -ENOMEM;
191
192         rc = CIFSFormatMFSymlink(buf, CIFS_MF_SYMLINK_FILE_SIZE, toName);
193         if (rc != 0) {
194                 kfree(buf);
195                 return rc;
196         }
197
198         rc = CIFSSMBOpen(xid, tcon, fromName, FILE_CREATE, GENERIC_WRITE,
199                          CREATE_NOT_DIR, &netfid, &oplock, NULL,
200                          nls_codepage, remap);
201         if (rc != 0) {
202                 kfree(buf);
203                 return rc;
204         }
205
206         rc = CIFSSMBWrite(xid, tcon, netfid,
207                           CIFS_MF_SYMLINK_FILE_SIZE /* length */,
208                           0 /* offset */,
209                           &bytes_written, buf, NULL, 0);
210         CIFSSMBClose(xid, tcon, netfid);
211         kfree(buf);
212         if (rc != 0)
213                 return rc;
214
215         if (bytes_written != CIFS_MF_SYMLINK_FILE_SIZE)
216                 return -EIO;
217
218         return 0;
219 }
220
221 static int
222 CIFSQueryMFSymLink(const int xid, struct cifsTconInfo *tcon,
223                    const unsigned char *searchName, char **symlinkinfo,
224                    const struct nls_table *nls_codepage, int remap)
225 {
226         int rc;
227         int oplock = 0;
228         __u16 netfid = 0;
229         u8 *buf;
230         char *pbuf;
231         unsigned int bytes_read = 0;
232         int buf_type = CIFS_NO_BUFFER;
233         unsigned int link_len = 0;
234         FILE_ALL_INFO file_info;
235
236         rc = CIFSSMBOpen(xid, tcon, searchName, FILE_OPEN, GENERIC_READ,
237                          CREATE_NOT_DIR, &netfid, &oplock, &file_info,
238                          nls_codepage, remap);
239         if (rc != 0)
240                 return rc;
241
242         if (file_info.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) {
243                 CIFSSMBClose(xid, tcon, netfid);
244                 /* it's not a symlink */
245                 return -EINVAL;
246         }
247
248         buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL);
249         if (!buf)
250                 return -ENOMEM;
251         pbuf = buf;
252
253         rc = CIFSSMBRead(xid, tcon, netfid,
254                          CIFS_MF_SYMLINK_FILE_SIZE /* length */,
255                          0 /* offset */,
256                          &bytes_read, &pbuf, &buf_type);
257         CIFSSMBClose(xid, tcon, netfid);
258         if (rc != 0) {
259                 kfree(buf);
260                 return rc;
261         }
262
263         rc = CIFSParseMFSymlink(buf, bytes_read, &link_len, symlinkinfo);
264         kfree(buf);
265         if (rc != 0)
266                 return rc;
267
268         return 0;
269 }
270
271 bool
272 CIFSCouldBeMFSymlink(const struct cifs_fattr *fattr)
273 {
274         if (!(fattr->cf_mode & S_IFREG))
275                 /* it's not a symlink */
276                 return false;
277
278         if (fattr->cf_eof != CIFS_MF_SYMLINK_FILE_SIZE)
279                 /* it's not a symlink */
280                 return false;
281
282         return true;
283 }
284
285 int
286 CIFSCheckMFSymlink(struct cifs_fattr *fattr,
287                    const unsigned char *path,
288                    struct cifs_sb_info *cifs_sb, int xid)
289 {
290         int rc;
291         int oplock = 0;
292         __u16 netfid = 0;
293         struct tcon_link *tlink;
294         struct cifsTconInfo *pTcon;
295         u8 *buf;
296         char *pbuf;
297         unsigned int bytes_read = 0;
298         int buf_type = CIFS_NO_BUFFER;
299         unsigned int link_len = 0;
300         FILE_ALL_INFO file_info;
301
302         if (!CIFSCouldBeMFSymlink(fattr))
303                 /* it's not a symlink */
304                 return 0;
305
306         tlink = cifs_sb_tlink(cifs_sb);
307         if (IS_ERR(tlink))
308                 return PTR_ERR(tlink);
309         pTcon = tlink_tcon(tlink);
310
311         rc = CIFSSMBOpen(xid, pTcon, path, FILE_OPEN, GENERIC_READ,
312                          CREATE_NOT_DIR, &netfid, &oplock, &file_info,
313                          cifs_sb->local_nls,
314                          cifs_sb->mnt_cifs_flags &
315                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
316         if (rc != 0)
317                 goto out;
318
319         if (file_info.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) {
320                 CIFSSMBClose(xid, pTcon, netfid);
321                 /* it's not a symlink */
322                 goto out;
323         }
324
325         buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL);
326         if (!buf) {
327                 rc = -ENOMEM;
328                 goto out;
329         }
330         pbuf = buf;
331
332         rc = CIFSSMBRead(xid, pTcon, netfid,
333                          CIFS_MF_SYMLINK_FILE_SIZE /* length */,
334                          0 /* offset */,
335                          &bytes_read, &pbuf, &buf_type);
336         CIFSSMBClose(xid, pTcon, netfid);
337         if (rc != 0) {
338                 kfree(buf);
339                 goto out;
340         }
341
342         rc = CIFSParseMFSymlink(buf, bytes_read, &link_len, NULL);
343         kfree(buf);
344         if (rc == -EINVAL) {
345                 /* it's not a symlink */
346                 rc = 0;
347                 goto out;
348         }
349
350         if (rc != 0)
351                 goto out;
352
353         /* it is a symlink */
354         fattr->cf_eof = link_len;
355         fattr->cf_mode &= ~S_IFMT;
356         fattr->cf_mode |= S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO;
357         fattr->cf_dtype = DT_LNK;
358 out:
359         cifs_put_tlink(tlink);
360         return rc;
361 }
362
363 int
364 cifs_hardlink(struct dentry *old_file, struct inode *inode,
365               struct dentry *direntry)
366 {
367         int rc = -EACCES;
368         int xid;
369         char *fromName = NULL;
370         char *toName = NULL;
371         struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
372         struct tcon_link *tlink;
373         struct cifsTconInfo *pTcon;
374         struct cifsInodeInfo *cifsInode;
375
376         tlink = cifs_sb_tlink(cifs_sb);
377         if (IS_ERR(tlink))
378                 return PTR_ERR(tlink);
379         pTcon = tlink_tcon(tlink);
380
381         xid = GetXid();
382
383         fromName = build_path_from_dentry(old_file);
384         toName = build_path_from_dentry(direntry);
385         if ((fromName == NULL) || (toName == NULL)) {
386                 rc = -ENOMEM;
387                 goto cifs_hl_exit;
388         }
389
390         if (pTcon->unix_ext)
391                 rc = CIFSUnixCreateHardLink(xid, pTcon, fromName, toName,
392                                             cifs_sb->local_nls,
393                                             cifs_sb->mnt_cifs_flags &
394                                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
395         else {
396                 rc = CIFSCreateHardLink(xid, pTcon, fromName, toName,
397                                         cifs_sb->local_nls,
398                                         cifs_sb->mnt_cifs_flags &
399                                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
400                 if ((rc == -EIO) || (rc == -EINVAL))
401                         rc = -EOPNOTSUPP;
402         }
403
404         d_drop(direntry);       /* force new lookup from server of target */
405
406         /* if source file is cached (oplocked) revalidate will not go to server
407            until the file is closed or oplock broken so update nlinks locally */
408         if (old_file->d_inode) {
409                 cifsInode = CIFS_I(old_file->d_inode);
410                 if (rc == 0) {
411                         old_file->d_inode->i_nlink++;
412 /* BB should we make this contingent on superblock flag NOATIME? */
413 /*                      old_file->d_inode->i_ctime = CURRENT_TIME;*/
414                         /* parent dir timestamps will update from srv
415                         within a second, would it really be worth it
416                         to set the parent dir cifs inode time to zero
417                         to force revalidate (faster) for it too? */
418                 }
419                 /* if not oplocked will force revalidate to get info
420                    on source file from srv */
421                 cifsInode->time = 0;
422
423                 /* Will update parent dir timestamps from srv within a second.
424                    Would it really be worth it to set the parent dir (cifs
425                    inode) time field to zero to force revalidate on parent
426                    directory faster ie
427                         CIFS_I(inode)->time = 0;  */
428         }
429
430 cifs_hl_exit:
431         kfree(fromName);
432         kfree(toName);
433         FreeXid(xid);
434         cifs_put_tlink(tlink);
435         return rc;
436 }
437
438 void *
439 cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
440 {
441         struct inode *inode = direntry->d_inode;
442         int rc = -ENOMEM;
443         int xid;
444         char *full_path = NULL;
445         char *target_path = NULL;
446         struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
447         struct tcon_link *tlink = NULL;
448         struct cifsTconInfo *tcon;
449
450         xid = GetXid();
451
452         tlink = cifs_sb_tlink(cifs_sb);
453         if (IS_ERR(tlink)) {
454                 rc = PTR_ERR(tlink);
455                 tlink = NULL;
456                 goto out;
457         }
458         tcon = tlink_tcon(tlink);
459
460         /*
461          * For now, we just handle symlinks with unix extensions enabled.
462          * Eventually we should handle NTFS reparse points, and MacOS
463          * symlink support. For instance...
464          *
465          * rc = CIFSSMBQueryReparseLinkInfo(...)
466          *
467          * For now, just return -EACCES when the server doesn't support posix
468          * extensions. Note that we still allow querying symlinks when posix
469          * extensions are manually disabled. We could disable these as well
470          * but there doesn't seem to be any harm in allowing the client to
471          * read them.
472          */
473         if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS)
474             && !(tcon->ses->capabilities & CAP_UNIX)) {
475                 rc = -EACCES;
476                 goto out;
477         }
478
479         full_path = build_path_from_dentry(direntry);
480         if (!full_path)
481                 goto out;
482
483         cFYI(1, "Full path: %s inode = 0x%p", full_path, inode);
484
485         rc = -EACCES;
486         /*
487          * First try Minshall+French Symlinks, if configured
488          * and fallback to UNIX Extensions Symlinks.
489          */
490         if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS)
491                 rc = CIFSQueryMFSymLink(xid, tcon, full_path, &target_path,
492                                         cifs_sb->local_nls,
493                                         cifs_sb->mnt_cifs_flags &
494                                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
495
496         if ((rc != 0) && (tcon->ses->capabilities & CAP_UNIX))
497                 rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, &target_path,
498                                              cifs_sb->local_nls);
499
500         kfree(full_path);
501 out:
502         if (rc != 0) {
503                 kfree(target_path);
504                 target_path = ERR_PTR(rc);
505         }
506
507         FreeXid(xid);
508         if (tlink)
509                 cifs_put_tlink(tlink);
510         nd_set_link(nd, target_path);
511         return NULL;
512 }
513
514 int
515 cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
516 {
517         int rc = -EOPNOTSUPP;
518         int xid;
519         struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
520         struct tcon_link *tlink;
521         struct cifsTconInfo *pTcon;
522         char *full_path = NULL;
523         struct inode *newinode = NULL;
524
525         xid = GetXid();
526
527         tlink = cifs_sb_tlink(cifs_sb);
528         if (IS_ERR(tlink)) {
529                 rc = PTR_ERR(tlink);
530                 goto symlink_exit;
531         }
532         pTcon = tlink_tcon(tlink);
533
534         full_path = build_path_from_dentry(direntry);
535         if (full_path == NULL) {
536                 rc = -ENOMEM;
537                 goto symlink_exit;
538         }
539
540         cFYI(1, "Full path: %s", full_path);
541         cFYI(1, "symname is %s", symname);
542
543         /* BB what if DFS and this volume is on different share? BB */
544         if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS)
545                 rc = CIFSCreateMFSymLink(xid, pTcon, full_path, symname,
546                                          cifs_sb->local_nls,
547                                          cifs_sb->mnt_cifs_flags &
548                                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
549         else if (pTcon->unix_ext)
550                 rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname,
551                                            cifs_sb->local_nls);
552         /* else
553            rc = CIFSCreateReparseSymLink(xid, pTcon, fromName, toName,
554                                         cifs_sb_target->local_nls); */
555
556         if (rc == 0) {
557                 if (pTcon->unix_ext)
558                         rc = cifs_get_inode_info_unix(&newinode, full_path,
559                                                       inode->i_sb, xid);
560                 else
561                         rc = cifs_get_inode_info(&newinode, full_path, NULL,
562                                                  inode->i_sb, xid, NULL);
563
564                 if (rc != 0) {
565                         cFYI(1, "Create symlink ok, getinodeinfo fail rc = %d",
566                               rc);
567                 } else {
568                         d_instantiate(direntry, newinode);
569                 }
570         }
571 symlink_exit:
572         kfree(full_path);
573         cifs_put_tlink(tlink);
574         FreeXid(xid);
575         return rc;
576 }
577
578 void cifs_put_link(struct dentry *direntry, struct nameidata *nd, void *cookie)
579 {
580         char *p = nd_get_link(nd);
581         if (!IS_ERR(p))
582                 kfree(p);
583 }