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