1// SPDX-License-Identifier: LGPL-2.1
2/*
3 *
4 *   Copyright (C) International Business Machines  Corp., 2002,2008
5 *   Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 */
8#include <linux/fs.h>
9#include <linux/stat.h>
10#include <linux/slab.h>
11#include <linux/namei.h>
12#include "cifsfs.h"
13#include "cifspdu.h"
14#include "cifsglob.h"
15#include "cifsproto.h"
16#include "cifs_debug.h"
17#include "cifs_fs_sb.h"
18#include "cifs_unicode.h"
19#include "smb2proto.h"
20#include "cifs_ioctl.h"
21
22/*
23 * M-F Symlink Functions - Begin
24 */
25
26#define CIFS_MF_SYMLINK_LEN_OFFSET (4+1)
27#define CIFS_MF_SYMLINK_MD5_OFFSET (CIFS_MF_SYMLINK_LEN_OFFSET+(4+1))
28#define CIFS_MF_SYMLINK_LINK_OFFSET (CIFS_MF_SYMLINK_MD5_OFFSET+(32+1))
29#define CIFS_MF_SYMLINK_LINK_MAXLEN (1024)
30#define CIFS_MF_SYMLINK_FILE_SIZE \
31	(CIFS_MF_SYMLINK_LINK_OFFSET + CIFS_MF_SYMLINK_LINK_MAXLEN)
32
33#define CIFS_MF_SYMLINK_LEN_FORMAT "XSym\n%04u\n"
34#define CIFS_MF_SYMLINK_MD5_FORMAT "%16phN\n"
35#define CIFS_MF_SYMLINK_MD5_ARGS(md5_hash) md5_hash
36
37static int
38symlink_hash(unsigned int link_len, const char *link_str, u8 *md5_hash)
39{
40	int rc;
41	struct shash_desc *md5 = NULL;
42
43	rc = cifs_alloc_hash("md5", &md5);
44	if (rc)
45		return rc;
46
47	rc = crypto_shash_digest(md5, link_str, link_len, md5_hash);
48	if (rc)
49		cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__);
50	cifs_free_hash(&md5);
51	return rc;
52}
53
54static int
55parse_mf_symlink(const u8 *buf, unsigned int buf_len, unsigned int *_link_len,
56		 char **_link_str)
57{
58	int rc;
59	unsigned int link_len;
60	const char *md5_str1;
61	const char *link_str;
62	u8 md5_hash[16];
63	char md5_str2[34];
64
65	if (buf_len != CIFS_MF_SYMLINK_FILE_SIZE)
66		return -EINVAL;
67
68	md5_str1 = (const char *)&buf[CIFS_MF_SYMLINK_MD5_OFFSET];
69	link_str = (const char *)&buf[CIFS_MF_SYMLINK_LINK_OFFSET];
70
71	rc = sscanf(buf, CIFS_MF_SYMLINK_LEN_FORMAT, &link_len);
72	if (rc != 1)
73		return -EINVAL;
74
75	if (link_len > CIFS_MF_SYMLINK_LINK_MAXLEN)
76		return -EINVAL;
77
78	rc = symlink_hash(link_len, link_str, md5_hash);
79	if (rc) {
80		cifs_dbg(FYI, "%s: MD5 hash failure: %d\n", __func__, rc);
81		return rc;
82	}
83
84	scnprintf(md5_str2, sizeof(md5_str2),
85		  CIFS_MF_SYMLINK_MD5_FORMAT,
86		  CIFS_MF_SYMLINK_MD5_ARGS(md5_hash));
87
88	if (strncmp(md5_str1, md5_str2, 17) != 0)
89		return -EINVAL;
90
91	if (_link_str) {
92		*_link_str = kstrndup(link_str, link_len, GFP_KERNEL);
93		if (!*_link_str)
94			return -ENOMEM;
95	}
96
97	*_link_len = link_len;
98	return 0;
99}
100
101static int
102format_mf_symlink(u8 *buf, unsigned int buf_len, const char *link_str)
103{
104	int rc;
105	unsigned int link_len;
106	unsigned int ofs;
107	u8 md5_hash[16];
108
109	if (buf_len != CIFS_MF_SYMLINK_FILE_SIZE)
110		return -EINVAL;
111
112	link_len = strlen(link_str);
113
114	if (link_len > CIFS_MF_SYMLINK_LINK_MAXLEN)
115		return -ENAMETOOLONG;
116
117	rc = symlink_hash(link_len, link_str, md5_hash);
118	if (rc) {
119		cifs_dbg(FYI, "%s: MD5 hash failure: %d\n", __func__, rc);
120		return rc;
121	}
122
123	scnprintf(buf, buf_len,
124		  CIFS_MF_SYMLINK_LEN_FORMAT CIFS_MF_SYMLINK_MD5_FORMAT,
125		  link_len,
126		  CIFS_MF_SYMLINK_MD5_ARGS(md5_hash));
127
128	ofs = CIFS_MF_SYMLINK_LINK_OFFSET;
129	memcpy(buf + ofs, link_str, link_len);
130
131	ofs += link_len;
132	if (ofs < CIFS_MF_SYMLINK_FILE_SIZE) {
133		buf[ofs] = '\n';
134		ofs++;
135	}
136
137	while (ofs < CIFS_MF_SYMLINK_FILE_SIZE) {
138		buf[ofs] = ' ';
139		ofs++;
140	}
141
142	return 0;
143}
144
145bool
146couldbe_mf_symlink(const struct cifs_fattr *fattr)
147{
148	if (!S_ISREG(fattr->cf_mode))
149		/* it's not a symlink */
150		return false;
151
152	if (fattr->cf_eof != CIFS_MF_SYMLINK_FILE_SIZE)
153		/* it's not a symlink */
154		return false;
155
156	return true;
157}
158
159static int
160create_mf_symlink(const unsigned int xid, struct cifs_tcon *tcon,
161		  struct cifs_sb_info *cifs_sb, const char *fromName,
162		  const char *toName)
163{
164	int rc;
165	u8 *buf;
166	unsigned int bytes_written = 0;
167
168	buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL);
169	if (!buf)
170		return -ENOMEM;
171
172	rc = format_mf_symlink(buf, CIFS_MF_SYMLINK_FILE_SIZE, toName);
173	if (rc)
174		goto out;
175
176	if (tcon->ses->server->ops->create_mf_symlink)
177		rc = tcon->ses->server->ops->create_mf_symlink(xid, tcon,
178					cifs_sb, fromName, buf, &bytes_written);
179	else
180		rc = -EOPNOTSUPP;
181
182	if (rc)
183		goto out;
184
185	if (bytes_written != CIFS_MF_SYMLINK_FILE_SIZE)
186		rc = -EIO;
187out:
188	kfree(buf);
189	return rc;
190}
191
192int
193check_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
194		 struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
195		 const unsigned char *path)
196{
197	int rc;
198	u8 *buf = NULL;
199	unsigned int link_len = 0;
200	unsigned int bytes_read = 0;
201	char *symlink = NULL;
202
203	if (!couldbe_mf_symlink(fattr))
204		/* it's not a symlink */
205		return 0;
206
207	buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL);
208	if (!buf)
209		return -ENOMEM;
210
211	if (tcon->ses->server->ops->query_mf_symlink)
212		rc = tcon->ses->server->ops->query_mf_symlink(xid, tcon,
213					      cifs_sb, path, buf, &bytes_read);
214	else
215		rc = -ENOSYS;
216
217	if (rc)
218		goto out;
219
220	if (bytes_read == 0) /* not a symlink */
221		goto out;
222
223	rc = parse_mf_symlink(buf, bytes_read, &link_len, &symlink);
224	if (rc == -EINVAL) {
225		/* it's not a symlink */
226		rc = 0;
227		goto out;
228	}
229
230	if (rc != 0)
231		goto out;
232
233	/* it is a symlink */
234	fattr->cf_eof = link_len;
235	fattr->cf_mode &= ~S_IFMT;
236	fattr->cf_mode |= S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO;
237	fattr->cf_dtype = DT_LNK;
238	fattr->cf_symlink_target = symlink;
239out:
240	kfree(buf);
241	return rc;
242}
243
244#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
245/*
246 * SMB 1.0 Protocol specific functions
247 */
248
249int
250cifs_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
251		      struct cifs_sb_info *cifs_sb, const unsigned char *path,
252		      char *pbuf, unsigned int *pbytes_read)
253{
254	int rc;
255	int oplock = 0;
256	struct cifs_fid fid;
257	struct cifs_open_parms oparms;
258	struct cifs_io_parms io_parms = {0};
259	int buf_type = CIFS_NO_BUFFER;
260	FILE_ALL_INFO file_info;
261
262	oparms = (struct cifs_open_parms) {
263		.tcon = tcon,
264		.cifs_sb = cifs_sb,
265		.desired_access = GENERIC_READ,
266		.create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR),
267		.disposition = FILE_OPEN,
268		.path = path,
269		.fid = &fid,
270	};
271
272	rc = CIFS_open(xid, &oparms, &oplock, &file_info);
273	if (rc)
274		return rc;
275
276	if (file_info.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) {
277		rc = -ENOENT;
278		/* it's not a symlink */
279		goto out;
280	}
281
282	io_parms.netfid = fid.netfid;
283	io_parms.pid = current->tgid;
284	io_parms.tcon = tcon;
285	io_parms.offset = 0;
286	io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE;
287
288	rc = CIFSSMBRead(xid, &io_parms, pbytes_read, &pbuf, &buf_type);
289out:
290	CIFSSMBClose(xid, tcon, fid.netfid);
291	return rc;
292}
293
294int
295cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
296		       struct cifs_sb_info *cifs_sb, const unsigned char *path,
297		       char *pbuf, unsigned int *pbytes_written)
298{
299	int rc;
300	int oplock = 0;
301	struct cifs_fid fid;
302	struct cifs_open_parms oparms;
303	struct cifs_io_parms io_parms = {0};
304
305	oparms = (struct cifs_open_parms) {
306		.tcon = tcon,
307		.cifs_sb = cifs_sb,
308		.desired_access = GENERIC_WRITE,
309		.create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR),
310		.disposition = FILE_CREATE,
311		.path = path,
312		.fid = &fid,
313	};
314
315	rc = CIFS_open(xid, &oparms, &oplock, NULL);
316	if (rc)
317		return rc;
318
319	io_parms.netfid = fid.netfid;
320	io_parms.pid = current->tgid;
321	io_parms.tcon = tcon;
322	io_parms.offset = 0;
323	io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE;
324
325	rc = CIFSSMBWrite(xid, &io_parms, pbytes_written, pbuf);
326	CIFSSMBClose(xid, tcon, fid.netfid);
327	return rc;
328}
329#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
330
331/*
332 * SMB 2.1/SMB3 Protocol specific functions
333 */
334int
335smb3_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
336		      struct cifs_sb_info *cifs_sb, const unsigned char *path,
337		      char *pbuf, unsigned int *pbytes_read)
338{
339	int rc;
340	struct cifs_fid fid;
341	struct cifs_open_parms oparms;
342	struct cifs_io_parms io_parms = {0};
343	int buf_type = CIFS_NO_BUFFER;
344	__le16 *utf16_path;
345	__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
346	struct smb2_file_all_info *pfile_info = NULL;
347
348	oparms = (struct cifs_open_parms) {
349		.tcon = tcon,
350		.cifs_sb = cifs_sb,
351		.path = path,
352		.desired_access = GENERIC_READ,
353		.create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR),
354		.disposition = FILE_OPEN,
355		.fid = &fid,
356	};
357
358	utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
359	if (utf16_path == NULL)
360		return -ENOMEM;
361
362	pfile_info = kzalloc(sizeof(struct smb2_file_all_info) + PATH_MAX * 2,
363			     GFP_KERNEL);
364
365	if (pfile_info == NULL) {
366		kfree(utf16_path);
367		return  -ENOMEM;
368	}
369
370	rc = SMB2_open(xid, &oparms, utf16_path, &oplock, pfile_info, NULL,
371		       NULL, NULL);
372	if (rc)
373		goto qmf_out_open_fail;
374
375	if (pfile_info->EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) {
376		/* it's not a symlink */
377		rc = -ENOENT; /* Is there a better rc to return? */
378		goto qmf_out;
379	}
380
381	io_parms.netfid = fid.netfid;
382	io_parms.pid = current->tgid;
383	io_parms.tcon = tcon;
384	io_parms.offset = 0;
385	io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE;
386	io_parms.persistent_fid = fid.persistent_fid;
387	io_parms.volatile_fid = fid.volatile_fid;
388	rc = SMB2_read(xid, &io_parms, pbytes_read, &pbuf, &buf_type);
389qmf_out:
390	SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
391qmf_out_open_fail:
392	kfree(utf16_path);
393	kfree(pfile_info);
394	return rc;
395}
396
397int
398smb3_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
399		       struct cifs_sb_info *cifs_sb, const unsigned char *path,
400		       char *pbuf, unsigned int *pbytes_written)
401{
402	int rc;
403	struct cifs_fid fid;
404	struct cifs_open_parms oparms;
405	struct cifs_io_parms io_parms = {0};
406	__le16 *utf16_path;
407	__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
408	struct kvec iov[2];
409
410	cifs_dbg(FYI, "%s: path: %s\n", __func__, path);
411
412	utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
413	if (!utf16_path)
414		return -ENOMEM;
415
416	oparms = (struct cifs_open_parms) {
417		.tcon = tcon,
418		.cifs_sb = cifs_sb,
419		.path = path,
420		.desired_access = GENERIC_WRITE,
421		.create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR),
422		.disposition = FILE_CREATE,
423		.fid = &fid,
424		.mode = 0644,
425	};
426
427	rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL,
428		       NULL, NULL);
429	if (rc) {
430		kfree(utf16_path);
431		return rc;
432	}
433
434	io_parms.netfid = fid.netfid;
435	io_parms.pid = current->tgid;
436	io_parms.tcon = tcon;
437	io_parms.offset = 0;
438	io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE;
439	io_parms.persistent_fid = fid.persistent_fid;
440	io_parms.volatile_fid = fid.volatile_fid;
441
442	/* iov[0] is reserved for smb header */
443	iov[1].iov_base = pbuf;
444	iov[1].iov_len = CIFS_MF_SYMLINK_FILE_SIZE;
445
446	rc = SMB2_write(xid, &io_parms, pbytes_written, iov, 1);
447
448	/* Make sure we wrote all of the symlink data */
449	if ((rc == 0) && (*pbytes_written != CIFS_MF_SYMLINK_FILE_SIZE))
450		rc = -EIO;
451
452	SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
453
454	kfree(utf16_path);
455	return rc;
456}
457
458/*
459 * M-F Symlink Functions - End
460 */
461
462int
463cifs_hardlink(struct dentry *old_file, struct inode *inode,
464	      struct dentry *direntry)
465{
466	int rc = -EACCES;
467	unsigned int xid;
468	const char *from_name, *to_name;
469	void *page1, *page2;
470	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
471	struct tcon_link *tlink;
472	struct cifs_tcon *tcon;
473	struct TCP_Server_Info *server;
474	struct cifsInodeInfo *cifsInode;
475
476	if (unlikely(cifs_forced_shutdown(cifs_sb)))
477		return -EIO;
478
479	tlink = cifs_sb_tlink(cifs_sb);
480	if (IS_ERR(tlink))
481		return PTR_ERR(tlink);
482	tcon = tlink_tcon(tlink);
483
484	xid = get_xid();
485	page1 = alloc_dentry_path();
486	page2 = alloc_dentry_path();
487
488	from_name = build_path_from_dentry(old_file, page1);
489	if (IS_ERR(from_name)) {
490		rc = PTR_ERR(from_name);
491		goto cifs_hl_exit;
492	}
493	to_name = build_path_from_dentry(direntry, page2);
494	if (IS_ERR(to_name)) {
495		rc = PTR_ERR(to_name);
496		goto cifs_hl_exit;
497	}
498
499#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
500	if (tcon->unix_ext)
501		rc = CIFSUnixCreateHardLink(xid, tcon, from_name, to_name,
502					    cifs_sb->local_nls,
503					    cifs_remap(cifs_sb));
504	else {
505#else
506	{
507#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
508		server = tcon->ses->server;
509		if (!server->ops->create_hardlink) {
510			rc = -ENOSYS;
511			goto cifs_hl_exit;
512		}
513		rc = server->ops->create_hardlink(xid, tcon, old_file,
514						  from_name, to_name, cifs_sb);
515		if ((rc == -EIO) || (rc == -EINVAL))
516			rc = -EOPNOTSUPP;
517	}
518
519	d_drop(direntry);	/* force new lookup from server of target */
520
521	/*
522	 * if source file is cached (oplocked) revalidate will not go to server
523	 * until the file is closed or oplock broken so update nlinks locally
524	 */
525	if (d_really_is_positive(old_file)) {
526		cifsInode = CIFS_I(d_inode(old_file));
527		if (rc == 0) {
528			spin_lock(&d_inode(old_file)->i_lock);
529			inc_nlink(d_inode(old_file));
530			spin_unlock(&d_inode(old_file)->i_lock);
531
532			/*
533			 * parent dir timestamps will update from srv within a
534			 * second, would it really be worth it to set the parent
535			 * dir cifs inode time to zero to force revalidate
536			 * (faster) for it too?
537			 */
538		}
539		/*
540		 * if not oplocked will force revalidate to get info on source
541		 * file from srv.  Note Samba server prior to 4.2 has bug -
542		 * not updating src file ctime on hardlinks but Windows servers
543		 * handle it properly
544		 */
545		cifsInode->time = 0;
546
547		/*
548		 * Will update parent dir timestamps from srv within a second.
549		 * Would it really be worth it to set the parent dir (cifs
550		 * inode) time field to zero to force revalidate on parent
551		 * directory faster ie
552		 *
553		 * CIFS_I(inode)->time = 0;
554		 */
555	}
556
557cifs_hl_exit:
558	free_dentry_path(page1);
559	free_dentry_path(page2);
560	free_xid(xid);
561	cifs_put_tlink(tlink);
562	return rc;
563}
564
565int
566cifs_symlink(struct mnt_idmap *idmap, struct inode *inode,
567	     struct dentry *direntry, const char *symname)
568{
569	int rc = -EOPNOTSUPP;
570	unsigned int xid;
571	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
572	struct TCP_Server_Info *server;
573	struct tcon_link *tlink;
574	struct cifs_tcon *pTcon;
575	const char *full_path;
576	void *page;
577	struct inode *newinode = NULL;
578
579	if (unlikely(cifs_forced_shutdown(cifs_sb)))
580		return -EIO;
581
582	page = alloc_dentry_path();
583	if (!page)
584		return -ENOMEM;
585
586	xid = get_xid();
587
588	tlink = cifs_sb_tlink(cifs_sb);
589	if (IS_ERR(tlink)) {
590		rc = PTR_ERR(tlink);
591		goto symlink_exit;
592	}
593	pTcon = tlink_tcon(tlink);
594	server = cifs_pick_channel(pTcon->ses);
595
596	full_path = build_path_from_dentry(direntry, page);
597	if (IS_ERR(full_path)) {
598		rc = PTR_ERR(full_path);
599		goto symlink_exit;
600	}
601
602	cifs_dbg(FYI, "Full path: %s\n", full_path);
603	cifs_dbg(FYI, "symname is %s\n", symname);
604
605	/* BB what if DFS and this volume is on different share? BB */
606	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
607		rc = create_mf_symlink(xid, pTcon, cifs_sb, full_path, symname);
608#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
609	} else if (pTcon->unix_ext) {
610		rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname,
611					   cifs_sb->local_nls,
612					   cifs_remap(cifs_sb));
613#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
614	} else if (server->ops->create_reparse_symlink) {
615		rc =  server->ops->create_reparse_symlink(xid, inode, direntry,
616							  pTcon, full_path,
617							  symname);
618		goto symlink_exit;
619	}
620
621	if (rc == 0) {
622		if (pTcon->posix_extensions) {
623			rc = smb311_posix_get_inode_info(&newinode, full_path,
624							 NULL, inode->i_sb, xid);
625		} else if (pTcon->unix_ext) {
626			rc = cifs_get_inode_info_unix(&newinode, full_path,
627						      inode->i_sb, xid);
628		} else {
629			rc = cifs_get_inode_info(&newinode, full_path, NULL,
630						 inode->i_sb, xid, NULL);
631		}
632
633		if (rc != 0) {
634			cifs_dbg(FYI, "Create symlink ok, getinodeinfo fail rc = %d\n",
635				 rc);
636		} else {
637			d_instantiate(direntry, newinode);
638		}
639	}
640symlink_exit:
641	free_dentry_path(page);
642	cifs_put_tlink(tlink);
643	free_xid(xid);
644	return rc;
645}
646