diff options
-rw-r--r-- | fs/cifs/Makefile | 3 | ||||
-rw-r--r-- | fs/cifs/cifsfs.c | 26 | ||||
-rw-r--r-- | fs/cifs/cifsfs.h | 12 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 4 | ||||
-rw-r--r-- | fs/cifs/xattr.c | 342 |
5 files changed, 167 insertions, 220 deletions
diff --git a/fs/cifs/Makefile b/fs/cifs/Makefile index 1964d212ab08..eed7eb09f46f 100644 --- a/fs/cifs/Makefile +++ b/fs/cifs/Makefile | |||
@@ -5,9 +5,10 @@ obj-$(CONFIG_CIFS) += cifs.o | |||
5 | 5 | ||
6 | cifs-y := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o \ | 6 | cifs-y := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o \ |
7 | link.o misc.o netmisc.o smbencrypt.o transport.o asn1.o \ | 7 | link.o misc.o netmisc.o smbencrypt.o transport.o asn1.o \ |
8 | cifs_unicode.o nterr.o xattr.o cifsencrypt.o \ | 8 | cifs_unicode.o nterr.o cifsencrypt.o \ |
9 | readdir.o ioctl.o sess.o export.o smb1ops.o winucase.o | 9 | readdir.o ioctl.o sess.o export.o smb1ops.o winucase.o |
10 | 10 | ||
11 | cifs-$(CONFIG_CIFS_XATTR) += xattr.o | ||
11 | cifs-$(CONFIG_CIFS_ACL) += cifsacl.o | 12 | cifs-$(CONFIG_CIFS_ACL) += cifsacl.o |
12 | 13 | ||
13 | cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o | 14 | cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o |
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index aadb59388e90..08fa36e5b2bc 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <linux/freezer.h> | 37 | #include <linux/freezer.h> |
38 | #include <linux/namei.h> | 38 | #include <linux/namei.h> |
39 | #include <linux/random.h> | 39 | #include <linux/random.h> |
40 | #include <linux/xattr.h> | ||
40 | #include <net/ipv6.h> | 41 | #include <net/ipv6.h> |
41 | #include "cifsfs.h" | 42 | #include "cifsfs.h" |
42 | #include "cifspdu.h" | 43 | #include "cifspdu.h" |
@@ -135,6 +136,7 @@ cifs_read_super(struct super_block *sb) | |||
135 | 136 | ||
136 | sb->s_magic = CIFS_MAGIC_NUMBER; | 137 | sb->s_magic = CIFS_MAGIC_NUMBER; |
137 | sb->s_op = &cifs_super_ops; | 138 | sb->s_op = &cifs_super_ops; |
139 | sb->s_xattr = cifs_xattr_handlers; | ||
138 | sb->s_bdi = &cifs_sb->bdi; | 140 | sb->s_bdi = &cifs_sb->bdi; |
139 | sb->s_blocksize = CIFS_MAX_MSGSIZE; | 141 | sb->s_blocksize = CIFS_MAX_MSGSIZE; |
140 | sb->s_blocksize_bits = 14; /* default 2**14 = CIFS_MAX_MSGSIZE */ | 142 | sb->s_blocksize_bits = 14; /* default 2**14 = CIFS_MAX_MSGSIZE */ |
@@ -892,12 +894,10 @@ const struct inode_operations cifs_dir_inode_ops = { | |||
892 | .setattr = cifs_setattr, | 894 | .setattr = cifs_setattr, |
893 | .symlink = cifs_symlink, | 895 | .symlink = cifs_symlink, |
894 | .mknod = cifs_mknod, | 896 | .mknod = cifs_mknod, |
895 | #ifdef CONFIG_CIFS_XATTR | 897 | .setxattr = generic_setxattr, |
896 | .setxattr = cifs_setxattr, | 898 | .getxattr = generic_getxattr, |
897 | .getxattr = cifs_getxattr, | ||
898 | .listxattr = cifs_listxattr, | 899 | .listxattr = cifs_listxattr, |
899 | .removexattr = cifs_removexattr, | 900 | .removexattr = generic_removexattr, |
900 | #endif | ||
901 | }; | 901 | }; |
902 | 902 | ||
903 | const struct inode_operations cifs_file_inode_ops = { | 903 | const struct inode_operations cifs_file_inode_ops = { |
@@ -905,12 +905,10 @@ const struct inode_operations cifs_file_inode_ops = { | |||
905 | .setattr = cifs_setattr, | 905 | .setattr = cifs_setattr, |
906 | .getattr = cifs_getattr, /* do we need this anymore? */ | 906 | .getattr = cifs_getattr, /* do we need this anymore? */ |
907 | .permission = cifs_permission, | 907 | .permission = cifs_permission, |
908 | #ifdef CONFIG_CIFS_XATTR | 908 | .setxattr = generic_setxattr, |
909 | .setxattr = cifs_setxattr, | 909 | .getxattr = generic_getxattr, |
910 | .getxattr = cifs_getxattr, | ||
911 | .listxattr = cifs_listxattr, | 910 | .listxattr = cifs_listxattr, |
912 | .removexattr = cifs_removexattr, | 911 | .removexattr = generic_removexattr, |
913 | #endif | ||
914 | }; | 912 | }; |
915 | 913 | ||
916 | const struct inode_operations cifs_symlink_inode_ops = { | 914 | const struct inode_operations cifs_symlink_inode_ops = { |
@@ -920,12 +918,10 @@ const struct inode_operations cifs_symlink_inode_ops = { | |||
920 | /* BB add the following two eventually */ | 918 | /* BB add the following two eventually */ |
921 | /* revalidate: cifs_revalidate, | 919 | /* revalidate: cifs_revalidate, |
922 | setattr: cifs_notify_change, *//* BB do we need notify change */ | 920 | setattr: cifs_notify_change, *//* BB do we need notify change */ |
923 | #ifdef CONFIG_CIFS_XATTR | 921 | .setxattr = generic_setxattr, |
924 | .setxattr = cifs_setxattr, | 922 | .getxattr = generic_getxattr, |
925 | .getxattr = cifs_getxattr, | ||
926 | .listxattr = cifs_listxattr, | 923 | .listxattr = cifs_listxattr, |
927 | .removexattr = cifs_removexattr, | 924 | .removexattr = generic_removexattr, |
928 | #endif | ||
929 | }; | 925 | }; |
930 | 926 | ||
931 | static int cifs_clone_file_range(struct file *src_file, loff_t off, | 927 | static int cifs_clone_file_range(struct file *src_file, loff_t off, |
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index c89ecd7a5c39..c1e749af749b 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h | |||
@@ -120,11 +120,15 @@ extern const char *cifs_get_link(struct dentry *, struct inode *, | |||
120 | struct delayed_call *); | 120 | struct delayed_call *); |
121 | extern int cifs_symlink(struct inode *inode, struct dentry *direntry, | 121 | extern int cifs_symlink(struct inode *inode, struct dentry *direntry, |
122 | const char *symname); | 122 | const char *symname); |
123 | extern int cifs_removexattr(struct dentry *, const char *); | 123 | |
124 | extern int cifs_setxattr(struct dentry *, const char *, const void *, | 124 | #ifdef CONFIG_CIFS_XATTR |
125 | size_t, int); | 125 | extern const struct xattr_handler *cifs_xattr_handlers[]; |
126 | extern ssize_t cifs_getxattr(struct dentry *, struct inode *, const char *, void *, size_t); | ||
127 | extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); | 126 | extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); |
127 | #else | ||
128 | # define cifs_xattr_handlers NULL | ||
129 | # define cifs_listxattr NULL | ||
130 | #endif | ||
131 | |||
128 | extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); | 132 | extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); |
129 | #ifdef CONFIG_CIFS_NFSD_EXPORT | 133 | #ifdef CONFIG_CIFS_NFSD_EXPORT |
130 | extern const struct export_operations cifs_export_ops; | 134 | extern const struct export_operations cifs_export_ops; |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index a894bf809ff7..145c03e75ee4 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -3366,7 +3366,7 @@ static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen, | |||
3366 | if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION) | 3366 | if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION) |
3367 | return -EOPNOTSUPP; | 3367 | return -EOPNOTSUPP; |
3368 | 3368 | ||
3369 | if (acl_type & ACL_TYPE_ACCESS) { | 3369 | if (acl_type == ACL_TYPE_ACCESS) { |
3370 | count = le16_to_cpu(cifs_acl->access_entry_count); | 3370 | count = le16_to_cpu(cifs_acl->access_entry_count); |
3371 | pACE = &cifs_acl->ace_array[0]; | 3371 | pACE = &cifs_acl->ace_array[0]; |
3372 | size = sizeof(struct cifs_posix_acl); | 3372 | size = sizeof(struct cifs_posix_acl); |
@@ -3377,7 +3377,7 @@ static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen, | |||
3377 | size_of_data_area, size); | 3377 | size_of_data_area, size); |
3378 | return -EINVAL; | 3378 | return -EINVAL; |
3379 | } | 3379 | } |
3380 | } else if (acl_type & ACL_TYPE_DEFAULT) { | 3380 | } else if (acl_type == ACL_TYPE_DEFAULT) { |
3381 | count = le16_to_cpu(cifs_acl->access_entry_count); | 3381 | count = le16_to_cpu(cifs_acl->access_entry_count); |
3382 | size = sizeof(struct cifs_posix_acl); | 3382 | size = sizeof(struct cifs_posix_acl); |
3383 | size += sizeof(struct cifs_posix_ace) * count; | 3383 | size += sizeof(struct cifs_posix_ace) * count; |
diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c index 5d57c85703a9..c8b77aa24a1d 100644 --- a/fs/cifs/xattr.c +++ b/fs/cifs/xattr.c | |||
@@ -32,68 +32,19 @@ | |||
32 | #include "cifs_unicode.h" | 32 | #include "cifs_unicode.h" |
33 | 33 | ||
34 | #define MAX_EA_VALUE_SIZE 65535 | 34 | #define MAX_EA_VALUE_SIZE 65535 |
35 | #define CIFS_XATTR_DOS_ATTRIB "user.DosAttrib" | ||
36 | #define CIFS_XATTR_CIFS_ACL "system.cifs_acl" | 35 | #define CIFS_XATTR_CIFS_ACL "system.cifs_acl" |
37 | 36 | ||
38 | /* BB need to add server (Samba e.g) support for security and trusted prefix */ | 37 | /* BB need to add server (Samba e.g) support for security and trusted prefix */ |
39 | 38 | ||
40 | int cifs_removexattr(struct dentry *direntry, const char *ea_name) | 39 | enum { XATTR_USER, XATTR_CIFS_ACL, XATTR_ACL_ACCESS, XATTR_ACL_DEFAULT }; |
41 | { | ||
42 | int rc = -EOPNOTSUPP; | ||
43 | #ifdef CONFIG_CIFS_XATTR | ||
44 | unsigned int xid; | ||
45 | struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb); | ||
46 | struct tcon_link *tlink; | ||
47 | struct cifs_tcon *pTcon; | ||
48 | char *full_path = NULL; | ||
49 | 40 | ||
50 | tlink = cifs_sb_tlink(cifs_sb); | 41 | static int cifs_xattr_set(const struct xattr_handler *handler, |
51 | if (IS_ERR(tlink)) | 42 | struct dentry *dentry, const char *name, |
52 | return PTR_ERR(tlink); | 43 | const void *value, size_t size, int flags) |
53 | pTcon = tlink_tcon(tlink); | ||
54 | |||
55 | xid = get_xid(); | ||
56 | |||
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 | |||
76 | ea_name += XATTR_USER_PREFIX_LEN; /* skip past user. prefix */ | ||
77 | if (pTcon->ses->server->ops->set_EA) | ||
78 | rc = pTcon->ses->server->ops->set_EA(xid, pTcon, | ||
79 | full_path, ea_name, NULL, (__u16)0, | ||
80 | cifs_sb->local_nls, cifs_remap(cifs_sb)); | ||
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 | |||
90 | int cifs_setxattr(struct dentry *direntry, const char *ea_name, | ||
91 | const void *ea_value, size_t value_size, int flags) | ||
92 | { | 44 | { |
93 | int rc = -EOPNOTSUPP; | 45 | int rc = -EOPNOTSUPP; |
94 | #ifdef CONFIG_CIFS_XATTR | ||
95 | unsigned int xid; | 46 | unsigned int xid; |
96 | struct super_block *sb = direntry->d_sb; | 47 | struct super_block *sb = dentry->d_sb; |
97 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | 48 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
98 | struct tcon_link *tlink; | 49 | struct tcon_link *tlink; |
99 | struct cifs_tcon *pTcon; | 50 | struct cifs_tcon *pTcon; |
@@ -106,10 +57,10 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name, | |||
106 | 57 | ||
107 | xid = get_xid(); | 58 | xid = get_xid(); |
108 | 59 | ||
109 | full_path = build_path_from_dentry(direntry); | 60 | full_path = build_path_from_dentry(dentry); |
110 | if (full_path == NULL) { | 61 | if (full_path == NULL) { |
111 | rc = -ENOMEM; | 62 | rc = -ENOMEM; |
112 | goto set_ea_exit; | 63 | goto out; |
113 | } | 64 | } |
114 | /* return dos attributes as pseudo xattr */ | 65 | /* return dos attributes as pseudo xattr */ |
115 | /* return alt name if available as pseudo attr */ | 66 | /* return alt name if available as pseudo attr */ |
@@ -117,109 +68,88 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name, | |||
117 | /* if proc/fs/cifs/streamstoxattr is set then | 68 | /* if proc/fs/cifs/streamstoxattr is set then |
118 | search server for EAs or streams to | 69 | search server for EAs or streams to |
119 | returns as xattrs */ | 70 | returns as xattrs */ |
120 | if (value_size > MAX_EA_VALUE_SIZE) { | 71 | if (size > MAX_EA_VALUE_SIZE) { |
121 | cifs_dbg(FYI, "size of EA value too large\n"); | 72 | cifs_dbg(FYI, "size of EA value too large\n"); |
122 | rc = -EOPNOTSUPP; | 73 | rc = -EOPNOTSUPP; |
123 | goto set_ea_exit; | 74 | goto out; |
124 | } | 75 | } |
125 | 76 | ||
126 | if (ea_name == NULL) { | 77 | switch (handler->flags) { |
127 | cifs_dbg(FYI, "Null xattr names not supported\n"); | 78 | case XATTR_USER: |
128 | } else if (strncmp(ea_name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN) | ||
129 | == 0) { | ||
130 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) | 79 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) |
131 | goto set_ea_exit; | 80 | goto out; |
132 | if (strncmp(ea_name, CIFS_XATTR_DOS_ATTRIB, 14) == 0) | ||
133 | cifs_dbg(FYI, "attempt to set cifs inode metadata\n"); | ||
134 | 81 | ||
135 | ea_name += XATTR_USER_PREFIX_LEN; /* skip past user. prefix */ | ||
136 | if (pTcon->ses->server->ops->set_EA) | 82 | if (pTcon->ses->server->ops->set_EA) |
137 | rc = pTcon->ses->server->ops->set_EA(xid, pTcon, | 83 | rc = pTcon->ses->server->ops->set_EA(xid, pTcon, |
138 | full_path, ea_name, ea_value, (__u16)value_size, | 84 | full_path, name, value, (__u16)size, |
139 | cifs_sb->local_nls, cifs_remap(cifs_sb)); | 85 | cifs_sb->local_nls, cifs_remap(cifs_sb)); |
140 | } else if (strncmp(ea_name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) | 86 | break; |
141 | == 0) { | ||
142 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) | ||
143 | goto set_ea_exit; | ||
144 | 87 | ||
145 | ea_name += XATTR_OS2_PREFIX_LEN; /* skip past os2. prefix */ | 88 | case XATTR_CIFS_ACL: { |
146 | if (pTcon->ses->server->ops->set_EA) | ||
147 | rc = pTcon->ses->server->ops->set_EA(xid, pTcon, | ||
148 | full_path, ea_name, ea_value, (__u16)value_size, | ||
149 | cifs_sb->local_nls, cifs_remap(cifs_sb)); | ||
150 | } else if (strncmp(ea_name, CIFS_XATTR_CIFS_ACL, | ||
151 | strlen(CIFS_XATTR_CIFS_ACL)) == 0) { | ||
152 | #ifdef CONFIG_CIFS_ACL | 89 | #ifdef CONFIG_CIFS_ACL |
153 | struct cifs_ntsd *pacl; | 90 | struct cifs_ntsd *pacl; |
154 | pacl = kmalloc(value_size, GFP_KERNEL); | 91 | |
92 | if (!value) | ||
93 | goto out; | ||
94 | pacl = kmalloc(size, GFP_KERNEL); | ||
155 | if (!pacl) { | 95 | if (!pacl) { |
156 | rc = -ENOMEM; | 96 | rc = -ENOMEM; |
157 | } else { | 97 | } else { |
158 | memcpy(pacl, ea_value, value_size); | 98 | memcpy(pacl, value, size); |
159 | if (pTcon->ses->server->ops->set_acl) | 99 | if (value && |
100 | pTcon->ses->server->ops->set_acl) | ||
160 | rc = pTcon->ses->server->ops->set_acl(pacl, | 101 | rc = pTcon->ses->server->ops->set_acl(pacl, |
161 | value_size, d_inode(direntry), | 102 | size, d_inode(dentry), |
162 | full_path, CIFS_ACL_DACL); | 103 | full_path, CIFS_ACL_DACL); |
163 | else | 104 | else |
164 | rc = -EOPNOTSUPP; | 105 | rc = -EOPNOTSUPP; |
165 | if (rc == 0) /* force revalidate of the inode */ | 106 | if (rc == 0) /* force revalidate of the inode */ |
166 | CIFS_I(d_inode(direntry))->time = 0; | 107 | CIFS_I(d_inode(dentry))->time = 0; |
167 | kfree(pacl); | 108 | kfree(pacl); |
168 | } | 109 | } |
169 | #else | ||
170 | cifs_dbg(FYI, "Set CIFS ACL not supported yet\n"); | ||
171 | #endif /* CONFIG_CIFS_ACL */ | 110 | #endif /* CONFIG_CIFS_ACL */ |
172 | } else { | 111 | break; |
173 | int temp; | 112 | } |
174 | temp = strncmp(ea_name, XATTR_NAME_POSIX_ACL_ACCESS, | 113 | |
175 | strlen(XATTR_NAME_POSIX_ACL_ACCESS)); | 114 | case XATTR_ACL_ACCESS: |
176 | if (temp == 0) { | ||
177 | #ifdef CONFIG_CIFS_POSIX | 115 | #ifdef CONFIG_CIFS_POSIX |
178 | if (sb->s_flags & MS_POSIXACL) | 116 | if (!value) |
179 | rc = CIFSSMBSetPosixACL(xid, pTcon, full_path, | 117 | goto out; |
180 | ea_value, (const int)value_size, | 118 | if (sb->s_flags & MS_POSIXACL) |
181 | ACL_TYPE_ACCESS, cifs_sb->local_nls, | 119 | rc = CIFSSMBSetPosixACL(xid, pTcon, full_path, |
182 | cifs_remap(cifs_sb)); | 120 | value, (const int)size, |
183 | cifs_dbg(FYI, "set POSIX ACL rc %d\n", rc); | 121 | ACL_TYPE_ACCESS, cifs_sb->local_nls, |
184 | #else | 122 | cifs_remap(cifs_sb)); |
185 | cifs_dbg(FYI, "set POSIX ACL not supported\n"); | 123 | #endif /* CONFIG_CIFS_POSIX */ |
186 | #endif | 124 | break; |
187 | } else if (strncmp(ea_name, XATTR_NAME_POSIX_ACL_DEFAULT, | 125 | |
188 | strlen(XATTR_NAME_POSIX_ACL_DEFAULT)) == 0) { | 126 | case XATTR_ACL_DEFAULT: |
189 | #ifdef CONFIG_CIFS_POSIX | 127 | #ifdef CONFIG_CIFS_POSIX |
190 | if (sb->s_flags & MS_POSIXACL) | 128 | if (!value) |
191 | rc = CIFSSMBSetPosixACL(xid, pTcon, full_path, | 129 | goto out; |
192 | ea_value, (const int)value_size, | 130 | if (sb->s_flags & MS_POSIXACL) |
193 | ACL_TYPE_DEFAULT, cifs_sb->local_nls, | 131 | rc = CIFSSMBSetPosixACL(xid, pTcon, full_path, |
194 | cifs_remap(cifs_sb)); | 132 | value, (const int)size, |
195 | cifs_dbg(FYI, "set POSIX default ACL rc %d\n", rc); | 133 | ACL_TYPE_DEFAULT, cifs_sb->local_nls, |
196 | #else | 134 | cifs_remap(cifs_sb)); |
197 | cifs_dbg(FYI, "set default POSIX ACL not supported\n"); | 135 | #endif /* CONFIG_CIFS_POSIX */ |
198 | #endif | 136 | break; |
199 | } else { | ||
200 | cifs_dbg(FYI, "illegal xattr request %s (only user namespace supported)\n", | ||
201 | ea_name); | ||
202 | /* BB what if no namespace prefix? */ | ||
203 | /* Should we just pass them to server, except for | ||
204 | system and perhaps security prefixes? */ | ||
205 | } | ||
206 | } | 137 | } |
207 | 138 | ||
208 | set_ea_exit: | 139 | out: |
209 | kfree(full_path); | 140 | kfree(full_path); |
210 | free_xid(xid); | 141 | free_xid(xid); |
211 | cifs_put_tlink(tlink); | 142 | cifs_put_tlink(tlink); |
212 | #endif | ||
213 | return rc; | 143 | return rc; |
214 | } | 144 | } |
215 | 145 | ||
216 | ssize_t cifs_getxattr(struct dentry *direntry, struct inode *inode, | 146 | static int cifs_xattr_get(const struct xattr_handler *handler, |
217 | const char *ea_name, void *ea_value, size_t buf_size) | 147 | struct dentry *dentry, struct inode *inode, |
148 | const char *name, void *value, size_t size) | ||
218 | { | 149 | { |
219 | ssize_t rc = -EOPNOTSUPP; | 150 | ssize_t rc = -EOPNOTSUPP; |
220 | #ifdef CONFIG_CIFS_XATTR | ||
221 | unsigned int xid; | 151 | unsigned int xid; |
222 | struct super_block *sb = direntry->d_sb; | 152 | struct super_block *sb = dentry->d_sb; |
223 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | 153 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
224 | struct tcon_link *tlink; | 154 | struct tcon_link *tlink; |
225 | struct cifs_tcon *pTcon; | 155 | struct cifs_tcon *pTcon; |
@@ -232,98 +162,72 @@ ssize_t cifs_getxattr(struct dentry *direntry, struct inode *inode, | |||
232 | 162 | ||
233 | xid = get_xid(); | 163 | xid = get_xid(); |
234 | 164 | ||
235 | full_path = build_path_from_dentry(direntry); | 165 | full_path = build_path_from_dentry(dentry); |
236 | if (full_path == NULL) { | 166 | if (full_path == NULL) { |
237 | rc = -ENOMEM; | 167 | rc = -ENOMEM; |
238 | goto get_ea_exit; | 168 | goto out; |
239 | } | 169 | } |
240 | /* return dos attributes as pseudo xattr */ | 170 | /* return dos attributes as pseudo xattr */ |
241 | /* return alt name if available as pseudo attr */ | 171 | /* return alt name if available as pseudo attr */ |
242 | if (ea_name == NULL) { | 172 | switch (handler->flags) { |
243 | cifs_dbg(FYI, "Null xattr names not supported\n"); | 173 | case XATTR_USER: |
244 | } else if (strncmp(ea_name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN) | ||
245 | == 0) { | ||
246 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) | 174 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) |
247 | goto get_ea_exit; | 175 | goto out; |
248 | 176 | ||
249 | if (strncmp(ea_name, CIFS_XATTR_DOS_ATTRIB, 14) == 0) { | ||
250 | cifs_dbg(FYI, "attempt to query cifs inode metadata\n"); | ||
251 | /* revalidate/getattr then populate from inode */ | ||
252 | } /* BB add else when above is implemented */ | ||
253 | ea_name += XATTR_USER_PREFIX_LEN; /* skip past user. prefix */ | ||
254 | if (pTcon->ses->server->ops->query_all_EAs) | 177 | if (pTcon->ses->server->ops->query_all_EAs) |
255 | rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon, | 178 | rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon, |
256 | full_path, ea_name, ea_value, buf_size, | 179 | full_path, name, value, size, |
257 | cifs_sb->local_nls, cifs_remap(cifs_sb)); | 180 | cifs_sb->local_nls, cifs_remap(cifs_sb)); |
258 | } else if (strncmp(ea_name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) == 0) { | 181 | break; |
259 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) | ||
260 | goto get_ea_exit; | ||
261 | 182 | ||
262 | ea_name += XATTR_OS2_PREFIX_LEN; /* skip past os2. prefix */ | 183 | case XATTR_CIFS_ACL: { |
263 | if (pTcon->ses->server->ops->query_all_EAs) | 184 | #ifdef CONFIG_CIFS_ACL |
264 | rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon, | 185 | u32 acllen; |
265 | full_path, ea_name, ea_value, buf_size, | 186 | struct cifs_ntsd *pacl; |
266 | cifs_sb->local_nls, cifs_remap(cifs_sb)); | 187 | |
267 | } else if (strncmp(ea_name, XATTR_NAME_POSIX_ACL_ACCESS, | 188 | if (pTcon->ses->server->ops->get_acl == NULL) |
268 | strlen(XATTR_NAME_POSIX_ACL_ACCESS)) == 0) { | 189 | goto out; /* rc already EOPNOTSUPP */ |
190 | |||
191 | pacl = pTcon->ses->server->ops->get_acl(cifs_sb, | ||
192 | inode, full_path, &acllen); | ||
193 | if (IS_ERR(pacl)) { | ||
194 | rc = PTR_ERR(pacl); | ||
195 | cifs_dbg(VFS, "%s: error %zd getting sec desc\n", | ||
196 | __func__, rc); | ||
197 | } else { | ||
198 | if (value) { | ||
199 | if (acllen > size) | ||
200 | acllen = -ERANGE; | ||
201 | else | ||
202 | memcpy(value, pacl, acllen); | ||
203 | } | ||
204 | rc = acllen; | ||
205 | kfree(pacl); | ||
206 | } | ||
207 | #endif /* CONFIG_CIFS_ACL */ | ||
208 | break; | ||
209 | } | ||
210 | |||
211 | case XATTR_ACL_ACCESS: | ||
269 | #ifdef CONFIG_CIFS_POSIX | 212 | #ifdef CONFIG_CIFS_POSIX |
270 | if (sb->s_flags & MS_POSIXACL) | 213 | if (sb->s_flags & MS_POSIXACL) |
271 | rc = CIFSSMBGetPosixACL(xid, pTcon, full_path, | 214 | rc = CIFSSMBGetPosixACL(xid, pTcon, full_path, |
272 | ea_value, buf_size, ACL_TYPE_ACCESS, | 215 | value, size, ACL_TYPE_ACCESS, |
273 | cifs_sb->local_nls, | 216 | cifs_sb->local_nls, |
274 | cifs_remap(cifs_sb)); | 217 | cifs_remap(cifs_sb)); |
275 | #else | 218 | #endif /* CONFIG_CIFS_POSIX */ |
276 | cifs_dbg(FYI, "Query POSIX ACL not supported yet\n"); | 219 | break; |
277 | #endif /* CONFIG_CIFS_POSIX */ | 220 | |
278 | } else if (strncmp(ea_name, XATTR_NAME_POSIX_ACL_DEFAULT, | 221 | case XATTR_ACL_DEFAULT: |
279 | strlen(XATTR_NAME_POSIX_ACL_DEFAULT)) == 0) { | ||
280 | #ifdef CONFIG_CIFS_POSIX | 222 | #ifdef CONFIG_CIFS_POSIX |
281 | if (sb->s_flags & MS_POSIXACL) | 223 | if (sb->s_flags & MS_POSIXACL) |
282 | rc = CIFSSMBGetPosixACL(xid, pTcon, full_path, | 224 | rc = CIFSSMBGetPosixACL(xid, pTcon, full_path, |
283 | ea_value, buf_size, ACL_TYPE_DEFAULT, | 225 | value, size, ACL_TYPE_DEFAULT, |
284 | cifs_sb->local_nls, | 226 | cifs_sb->local_nls, |
285 | cifs_remap(cifs_sb)); | 227 | cifs_remap(cifs_sb)); |
286 | #else | 228 | #endif /* CONFIG_CIFS_POSIX */ |
287 | cifs_dbg(FYI, "Query POSIX default ACL not supported yet\n"); | 229 | break; |
288 | #endif /* CONFIG_CIFS_POSIX */ | 230 | } |
289 | } else if (strncmp(ea_name, CIFS_XATTR_CIFS_ACL, | ||
290 | strlen(CIFS_XATTR_CIFS_ACL)) == 0) { | ||
291 | #ifdef CONFIG_CIFS_ACL | ||
292 | u32 acllen; | ||
293 | struct cifs_ntsd *pacl; | ||
294 | |||
295 | if (pTcon->ses->server->ops->get_acl == NULL) | ||
296 | goto get_ea_exit; /* rc already EOPNOTSUPP */ | ||
297 | |||
298 | pacl = pTcon->ses->server->ops->get_acl(cifs_sb, | ||
299 | inode, full_path, &acllen); | ||
300 | if (IS_ERR(pacl)) { | ||
301 | rc = PTR_ERR(pacl); | ||
302 | cifs_dbg(VFS, "%s: error %zd getting sec desc\n", | ||
303 | __func__, rc); | ||
304 | } else { | ||
305 | if (ea_value) { | ||
306 | if (acllen > buf_size) | ||
307 | acllen = -ERANGE; | ||
308 | else | ||
309 | memcpy(ea_value, pacl, acllen); | ||
310 | } | ||
311 | rc = acllen; | ||
312 | kfree(pacl); | ||
313 | } | ||
314 | #else | ||
315 | cifs_dbg(FYI, "Query CIFS ACL not supported yet\n"); | ||
316 | #endif /* CONFIG_CIFS_ACL */ | ||
317 | } else if (strncmp(ea_name, | ||
318 | XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) == 0) { | ||
319 | cifs_dbg(FYI, "Trusted xattr namespace not supported yet\n"); | ||
320 | } else if (strncmp(ea_name, | ||
321 | XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) == 0) { | ||
322 | cifs_dbg(FYI, "Security xattr namespace not supported yet\n"); | ||
323 | } else | ||
324 | cifs_dbg(FYI, | ||
325 | "illegal xattr request %s (only user namespace supported)\n", | ||
326 | ea_name); | ||
327 | 231 | ||
328 | /* We could add an additional check for streams ie | 232 | /* We could add an additional check for streams ie |
329 | if proc/fs/cifs/streamstoxattr is set then | 233 | if proc/fs/cifs/streamstoxattr is set then |
@@ -333,18 +237,16 @@ ssize_t cifs_getxattr(struct dentry *direntry, struct inode *inode, | |||
333 | if (rc == -EINVAL) | 237 | if (rc == -EINVAL) |
334 | rc = -EOPNOTSUPP; | 238 | rc = -EOPNOTSUPP; |
335 | 239 | ||
336 | get_ea_exit: | 240 | out: |
337 | kfree(full_path); | 241 | kfree(full_path); |
338 | free_xid(xid); | 242 | free_xid(xid); |
339 | cifs_put_tlink(tlink); | 243 | cifs_put_tlink(tlink); |
340 | #endif | ||
341 | return rc; | 244 | return rc; |
342 | } | 245 | } |
343 | 246 | ||
344 | ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size) | 247 | ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size) |
345 | { | 248 | { |
346 | ssize_t rc = -EOPNOTSUPP; | 249 | ssize_t rc = -EOPNOTSUPP; |
347 | #ifdef CONFIG_CIFS_XATTR | ||
348 | unsigned int xid; | 250 | unsigned int xid; |
349 | struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb); | 251 | struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb); |
350 | struct tcon_link *tlink; | 252 | struct tcon_link *tlink; |
@@ -381,6 +283,50 @@ list_ea_exit: | |||
381 | kfree(full_path); | 283 | kfree(full_path); |
382 | free_xid(xid); | 284 | free_xid(xid); |
383 | cifs_put_tlink(tlink); | 285 | cifs_put_tlink(tlink); |
384 | #endif | ||
385 | return rc; | 286 | return rc; |
386 | } | 287 | } |
288 | |||
289 | static const struct xattr_handler cifs_user_xattr_handler = { | ||
290 | .prefix = XATTR_USER_PREFIX, | ||
291 | .flags = XATTR_USER, | ||
292 | .get = cifs_xattr_get, | ||
293 | .set = cifs_xattr_set, | ||
294 | }; | ||
295 | |||
296 | /* os2.* attributes are treated like user.* attributes */ | ||
297 | static const struct xattr_handler cifs_os2_xattr_handler = { | ||
298 | .prefix = XATTR_OS2_PREFIX, | ||
299 | .flags = XATTR_USER, | ||
300 | .get = cifs_xattr_get, | ||
301 | .set = cifs_xattr_set, | ||
302 | }; | ||
303 | |||
304 | static const struct xattr_handler cifs_cifs_acl_xattr_handler = { | ||
305 | .name = CIFS_XATTR_CIFS_ACL, | ||
306 | .flags = XATTR_CIFS_ACL, | ||
307 | .get = cifs_xattr_get, | ||
308 | .set = cifs_xattr_set, | ||
309 | }; | ||
310 | |||
311 | static const struct xattr_handler cifs_posix_acl_access_xattr_handler = { | ||
312 | .name = XATTR_NAME_POSIX_ACL_ACCESS, | ||
313 | .flags = XATTR_ACL_ACCESS, | ||
314 | .get = cifs_xattr_get, | ||
315 | .set = cifs_xattr_set, | ||
316 | }; | ||
317 | |||
318 | static const struct xattr_handler cifs_posix_acl_default_xattr_handler = { | ||
319 | .name = XATTR_NAME_POSIX_ACL_DEFAULT, | ||
320 | .flags = XATTR_ACL_DEFAULT, | ||
321 | .get = cifs_xattr_get, | ||
322 | .set = cifs_xattr_set, | ||
323 | }; | ||
324 | |||
325 | const struct xattr_handler *cifs_xattr_handlers[] = { | ||
326 | &cifs_user_xattr_handler, | ||
327 | &cifs_os2_xattr_handler, | ||
328 | &cifs_cifs_acl_xattr_handler, | ||
329 | &cifs_posix_acl_access_xattr_handler, | ||
330 | &cifs_posix_acl_default_xattr_handler, | ||
331 | NULL | ||
332 | }; | ||