xattr.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. /*
  2. * fs/cifs/xattr.c
  3. *
  4. * Copyright (c) International Business Machines Corp., 2003, 2007
  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/posix_acl_xattr.h>
  23. #include <linux/slab.h>
  24. #include <linux/xattr.h>
  25. #include "cifsfs.h"
  26. #include "cifspdu.h"
  27. #include "cifsglob.h"
  28. #include "cifsproto.h"
  29. #include "cifs_debug.h"
  30. #define MAX_EA_VALUE_SIZE 65535
  31. #define CIFS_XATTR_DOS_ATTRIB "user.DosAttrib"
  32. #define CIFS_XATTR_CIFS_ACL "system.cifs_acl"
  33. /* BB need to add server (Samba e.g) support for security and trusted prefix */
  34. int cifs_removexattr(struct dentry *direntry, const char *ea_name)
  35. {
  36. int rc = -EOPNOTSUPP;
  37. #ifdef CONFIG_CIFS_XATTR
  38. unsigned int xid;
  39. struct cifs_sb_info *cifs_sb;
  40. struct tcon_link *tlink;
  41. struct cifs_tcon *pTcon;
  42. struct super_block *sb;
  43. char *full_path = NULL;
  44. if (direntry == NULL)
  45. return -EIO;
  46. if (direntry->d_inode == NULL)
  47. return -EIO;
  48. sb = direntry->d_inode->i_sb;
  49. if (sb == NULL)
  50. return -EIO;
  51. cifs_sb = CIFS_SB(sb);
  52. tlink = cifs_sb_tlink(cifs_sb);
  53. if (IS_ERR(tlink))
  54. return PTR_ERR(tlink);
  55. pTcon = tlink_tcon(tlink);
  56. xid = get_xid();
  57. full_path = build_path_from_dentry(direntry);
  58. if (full_path == NULL) {
  59. rc = -ENOMEM;
  60. goto remove_ea_exit;
  61. }
  62. if (ea_name == NULL) {
  63. cifs_dbg(FYI, "Null xattr names not supported\n");
  64. } else if (strncmp(ea_name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)
  65. && (strncmp(ea_name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN))) {
  66. cifs_dbg(FYI,
  67. "illegal xattr request %s (only user namespace supported)\n",
  68. ea_name);
  69. /* BB what if no namespace prefix? */
  70. /* Should we just pass them to server, except for
  71. system and perhaps security prefixes? */
  72. } else {
  73. if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
  74. goto remove_ea_exit;
  75. ea_name += XATTR_USER_PREFIX_LEN; /* skip past user. prefix */
  76. if (pTcon->ses->server->ops->set_EA)
  77. rc = pTcon->ses->server->ops->set_EA(xid, pTcon,
  78. full_path, ea_name, NULL, (__u16)0,
  79. cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
  80. CIFS_MOUNT_MAP_SPECIAL_CHR);
  81. }
  82. remove_ea_exit:
  83. kfree(full_path);
  84. free_xid(xid);
  85. cifs_put_tlink(tlink);
  86. #endif
  87. return rc;
  88. }
  89. int cifs_setxattr(struct dentry *direntry, const char *ea_name,
  90. const void *ea_value, size_t value_size, int flags)
  91. {
  92. int rc = -EOPNOTSUPP;
  93. #ifdef CONFIG_CIFS_XATTR
  94. unsigned int xid;
  95. struct cifs_sb_info *cifs_sb;
  96. struct tcon_link *tlink;
  97. struct cifs_tcon *pTcon;
  98. struct super_block *sb;
  99. char *full_path;
  100. if (direntry == NULL)
  101. return -EIO;
  102. if (direntry->d_inode == NULL)
  103. return -EIO;
  104. sb = direntry->d_inode->i_sb;
  105. if (sb == NULL)
  106. return -EIO;
  107. cifs_sb = CIFS_SB(sb);
  108. tlink = cifs_sb_tlink(cifs_sb);
  109. if (IS_ERR(tlink))
  110. return PTR_ERR(tlink);
  111. pTcon = tlink_tcon(tlink);
  112. xid = get_xid();
  113. full_path = build_path_from_dentry(direntry);
  114. if (full_path == NULL) {
  115. rc = -ENOMEM;
  116. goto set_ea_exit;
  117. }
  118. /* return dos attributes as pseudo xattr */
  119. /* return alt name if available as pseudo attr */
  120. /* if proc/fs/cifs/streamstoxattr is set then
  121. search server for EAs or streams to
  122. returns as xattrs */
  123. if (value_size > MAX_EA_VALUE_SIZE) {
  124. cifs_dbg(FYI, "size of EA value too large\n");
  125. rc = -EOPNOTSUPP;
  126. goto set_ea_exit;
  127. }
  128. if (ea_name == NULL) {
  129. cifs_dbg(FYI, "Null xattr names not supported\n");
  130. } else if (strncmp(ea_name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)
  131. == 0) {
  132. if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
  133. goto set_ea_exit;
  134. if (strncmp(ea_name, CIFS_XATTR_DOS_ATTRIB, 14) == 0)
  135. cifs_dbg(FYI, "attempt to set cifs inode metadata\n");
  136. ea_name += XATTR_USER_PREFIX_LEN; /* skip past user. prefix */
  137. if (pTcon->ses->server->ops->set_EA)
  138. rc = pTcon->ses->server->ops->set_EA(xid, pTcon,
  139. full_path, ea_name, ea_value, (__u16)value_size,
  140. cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
  141. CIFS_MOUNT_MAP_SPECIAL_CHR);
  142. } else if (strncmp(ea_name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN)
  143. == 0) {
  144. if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
  145. goto set_ea_exit;
  146. ea_name += XATTR_OS2_PREFIX_LEN; /* skip past os2. prefix */
  147. if (pTcon->ses->server->ops->set_EA)
  148. rc = pTcon->ses->server->ops->set_EA(xid, pTcon,
  149. full_path, ea_name, ea_value, (__u16)value_size,
  150. cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
  151. CIFS_MOUNT_MAP_SPECIAL_CHR);
  152. } else if (strncmp(ea_name, CIFS_XATTR_CIFS_ACL,
  153. strlen(CIFS_XATTR_CIFS_ACL)) == 0) {
  154. #ifdef CONFIG_CIFS_ACL
  155. struct cifs_ntsd *pacl;
  156. pacl = kmalloc(value_size, GFP_KERNEL);
  157. if (!pacl) {
  158. rc = -ENOMEM;
  159. } else {
  160. memcpy(pacl, ea_value, value_size);
  161. if (pTcon->ses->server->ops->set_acl)
  162. rc = pTcon->ses->server->ops->set_acl(pacl,
  163. value_size, direntry->d_inode,
  164. full_path, CIFS_ACL_DACL);
  165. else
  166. rc = -EOPNOTSUPP;
  167. if (rc == 0) /* force revalidate of the inode */
  168. CIFS_I(direntry->d_inode)->time = 0;
  169. kfree(pacl);
  170. }
  171. #else
  172. cifs_dbg(FYI, "Set CIFS ACL not supported yet\n");
  173. #endif /* CONFIG_CIFS_ACL */
  174. } else {
  175. int temp;
  176. temp = strncmp(ea_name, POSIX_ACL_XATTR_ACCESS,
  177. strlen(POSIX_ACL_XATTR_ACCESS));
  178. if (temp == 0) {
  179. #ifdef CONFIG_CIFS_POSIX
  180. if (sb->s_flags & MS_POSIXACL)
  181. rc = CIFSSMBSetPosixACL(xid, pTcon, full_path,
  182. ea_value, (const int)value_size,
  183. ACL_TYPE_ACCESS, cifs_sb->local_nls,
  184. cifs_sb->mnt_cifs_flags &
  185. CIFS_MOUNT_MAP_SPECIAL_CHR);
  186. cifs_dbg(FYI, "set POSIX ACL rc %d\n", rc);
  187. #else
  188. cifs_dbg(FYI, "set POSIX ACL not supported\n");
  189. #endif
  190. } else if (strncmp(ea_name, POSIX_ACL_XATTR_DEFAULT,
  191. strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) {
  192. #ifdef CONFIG_CIFS_POSIX
  193. if (sb->s_flags & MS_POSIXACL)
  194. rc = CIFSSMBSetPosixACL(xid, pTcon, full_path,
  195. ea_value, (const int)value_size,
  196. ACL_TYPE_DEFAULT, cifs_sb->local_nls,
  197. cifs_sb->mnt_cifs_flags &
  198. CIFS_MOUNT_MAP_SPECIAL_CHR);
  199. cifs_dbg(FYI, "set POSIX default ACL rc %d\n", rc);
  200. #else
  201. cifs_dbg(FYI, "set default POSIX ACL not supported\n");
  202. #endif
  203. } else {
  204. cifs_dbg(FYI, "illegal xattr request %s (only user namespace supported)\n",
  205. ea_name);
  206. /* BB what if no namespace prefix? */
  207. /* Should we just pass them to server, except for
  208. system and perhaps security prefixes? */
  209. }
  210. }
  211. set_ea_exit:
  212. kfree(full_path);
  213. free_xid(xid);
  214. cifs_put_tlink(tlink);
  215. #endif
  216. return rc;
  217. }
  218. ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
  219. void *ea_value, size_t buf_size)
  220. {
  221. ssize_t rc = -EOPNOTSUPP;
  222. #ifdef CONFIG_CIFS_XATTR
  223. unsigned int xid;
  224. struct cifs_sb_info *cifs_sb;
  225. struct tcon_link *tlink;
  226. struct cifs_tcon *pTcon;
  227. struct super_block *sb;
  228. char *full_path;
  229. if (direntry == NULL)
  230. return -EIO;
  231. if (direntry->d_inode == NULL)
  232. return -EIO;
  233. sb = direntry->d_inode->i_sb;
  234. if (sb == NULL)
  235. return -EIO;
  236. cifs_sb = CIFS_SB(sb);
  237. tlink = cifs_sb_tlink(cifs_sb);
  238. if (IS_ERR(tlink))
  239. return PTR_ERR(tlink);
  240. pTcon = tlink_tcon(tlink);
  241. xid = get_xid();
  242. full_path = build_path_from_dentry(direntry);
  243. if (full_path == NULL) {
  244. rc = -ENOMEM;
  245. goto get_ea_exit;
  246. }
  247. /* return dos attributes as pseudo xattr */
  248. /* return alt name if available as pseudo attr */
  249. if (ea_name == NULL) {
  250. cifs_dbg(FYI, "Null xattr names not supported\n");
  251. } else if (strncmp(ea_name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)
  252. == 0) {
  253. if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
  254. goto get_ea_exit;
  255. if (strncmp(ea_name, CIFS_XATTR_DOS_ATTRIB, 14) == 0) {
  256. cifs_dbg(FYI, "attempt to query cifs inode metadata\n");
  257. /* revalidate/getattr then populate from inode */
  258. } /* BB add else when above is implemented */
  259. ea_name += XATTR_USER_PREFIX_LEN; /* skip past user. prefix */
  260. if (pTcon->ses->server->ops->query_all_EAs)
  261. rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon,
  262. full_path, ea_name, ea_value, buf_size,
  263. cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
  264. CIFS_MOUNT_MAP_SPECIAL_CHR);
  265. } else if (strncmp(ea_name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) == 0) {
  266. if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
  267. goto get_ea_exit;
  268. ea_name += XATTR_OS2_PREFIX_LEN; /* skip past os2. prefix */
  269. if (pTcon->ses->server->ops->query_all_EAs)
  270. rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon,
  271. full_path, ea_name, ea_value, buf_size,
  272. cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
  273. CIFS_MOUNT_MAP_SPECIAL_CHR);
  274. } else if (strncmp(ea_name, POSIX_ACL_XATTR_ACCESS,
  275. strlen(POSIX_ACL_XATTR_ACCESS)) == 0) {
  276. #ifdef CONFIG_CIFS_POSIX
  277. if (sb->s_flags & MS_POSIXACL)
  278. rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
  279. ea_value, buf_size, ACL_TYPE_ACCESS,
  280. cifs_sb->local_nls,
  281. cifs_sb->mnt_cifs_flags &
  282. CIFS_MOUNT_MAP_SPECIAL_CHR);
  283. #else
  284. cifs_dbg(FYI, "Query POSIX ACL not supported yet\n");
  285. #endif /* CONFIG_CIFS_POSIX */
  286. } else if (strncmp(ea_name, POSIX_ACL_XATTR_DEFAULT,
  287. strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) {
  288. #ifdef CONFIG_CIFS_POSIX
  289. if (sb->s_flags & MS_POSIXACL)
  290. rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
  291. ea_value, buf_size, ACL_TYPE_DEFAULT,
  292. cifs_sb->local_nls,
  293. cifs_sb->mnt_cifs_flags &
  294. CIFS_MOUNT_MAP_SPECIAL_CHR);
  295. #else
  296. cifs_dbg(FYI, "Query POSIX default ACL not supported yet\n");
  297. #endif /* CONFIG_CIFS_POSIX */
  298. } else if (strncmp(ea_name, CIFS_XATTR_CIFS_ACL,
  299. strlen(CIFS_XATTR_CIFS_ACL)) == 0) {
  300. #ifdef CONFIG_CIFS_ACL
  301. u32 acllen;
  302. struct cifs_ntsd *pacl;
  303. if (pTcon->ses->server->ops->get_acl == NULL)
  304. goto get_ea_exit; /* rc already EOPNOTSUPP */
  305. pacl = pTcon->ses->server->ops->get_acl(cifs_sb,
  306. direntry->d_inode, full_path, &acllen);
  307. if (IS_ERR(pacl)) {
  308. rc = PTR_ERR(pacl);
  309. cifs_dbg(VFS, "%s: error %zd getting sec desc\n",
  310. __func__, rc);
  311. } else {
  312. if (ea_value) {
  313. if (acllen > buf_size)
  314. acllen = -ERANGE;
  315. else
  316. memcpy(ea_value, pacl, acllen);
  317. }
  318. rc = acllen;
  319. kfree(pacl);
  320. }
  321. #else
  322. cifs_dbg(FYI, "Query CIFS ACL not supported yet\n");
  323. #endif /* CONFIG_CIFS_ACL */
  324. } else if (strncmp(ea_name,
  325. XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) == 0) {
  326. cifs_dbg(FYI, "Trusted xattr namespace not supported yet\n");
  327. } else if (strncmp(ea_name,
  328. XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) == 0) {
  329. cifs_dbg(FYI, "Security xattr namespace not supported yet\n");
  330. } else
  331. cifs_dbg(FYI,
  332. "illegal xattr request %s (only user namespace supported)\n",
  333. ea_name);
  334. /* We could add an additional check for streams ie
  335. if proc/fs/cifs/streamstoxattr is set then
  336. search server for EAs or streams to
  337. returns as xattrs */
  338. if (rc == -EINVAL)
  339. rc = -EOPNOTSUPP;
  340. get_ea_exit:
  341. kfree(full_path);
  342. free_xid(xid);
  343. cifs_put_tlink(tlink);
  344. #endif
  345. return rc;
  346. }
  347. ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size)
  348. {
  349. ssize_t rc = -EOPNOTSUPP;
  350. #ifdef CONFIG_CIFS_XATTR
  351. unsigned int xid;
  352. struct cifs_sb_info *cifs_sb;
  353. struct tcon_link *tlink;
  354. struct cifs_tcon *pTcon;
  355. struct super_block *sb;
  356. char *full_path;
  357. if (direntry == NULL)
  358. return -EIO;
  359. if (direntry->d_inode == NULL)
  360. return -EIO;
  361. sb = direntry->d_inode->i_sb;
  362. if (sb == NULL)
  363. return -EIO;
  364. cifs_sb = CIFS_SB(sb);
  365. if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
  366. return -EOPNOTSUPP;
  367. tlink = cifs_sb_tlink(cifs_sb);
  368. if (IS_ERR(tlink))
  369. return PTR_ERR(tlink);
  370. pTcon = tlink_tcon(tlink);
  371. xid = get_xid();
  372. full_path = build_path_from_dentry(direntry);
  373. if (full_path == NULL) {
  374. rc = -ENOMEM;
  375. goto list_ea_exit;
  376. }
  377. /* return dos attributes as pseudo xattr */
  378. /* return alt name if available as pseudo attr */
  379. /* if proc/fs/cifs/streamstoxattr is set then
  380. search server for EAs or streams to
  381. returns as xattrs */
  382. if (pTcon->ses->server->ops->query_all_EAs)
  383. rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon,
  384. full_path, NULL, data, buf_size,
  385. cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
  386. CIFS_MOUNT_MAP_SPECIAL_CHR);
  387. list_ea_exit:
  388. kfree(full_path);
  389. free_xid(xid);
  390. cifs_put_tlink(tlink);
  391. #endif
  392. return rc;
  393. }