1 | /* $NetBSD: vfs_xattr.c,v 1.33 2014/09/05 09:20:59 matt Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 2005, 2008 The NetBSD Foundation, Inc. |
5 | * All rights reserved. |
6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Jason R. Thorpe. |
9 | * |
10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions |
12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. |
18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ |
31 | |
32 | /* |
33 | * Copyright (c) 1989, 1993 |
34 | * The Regents of the University of California. All rights reserved. |
35 | * (c) UNIX System Laboratories, Inc. |
36 | * All or some portions of this file are derived from material licensed |
37 | * to the University of California by American Telephone and Telegraph |
38 | * Co. or Unix System Laboratories, Inc. and are reproduced herein with |
39 | * the permission of UNIX System Laboratories, Inc. |
40 | * |
41 | * Redistribution and use in source and binary forms, with or without |
42 | * modification, are permitted provided that the following conditions |
43 | * are met: |
44 | * 1. Redistributions of source code must retain the above copyright |
45 | * notice, this list of conditions and the following disclaimer. |
46 | * 2. Redistributions in binary form must reproduce the above copyright |
47 | * notice, this list of conditions and the following disclaimer in the |
48 | * documentation and/or other materials provided with the distribution. |
49 | * 3. Neither the name of the University nor the names of its contributors |
50 | * may be used to endorse or promote products derived from this software |
51 | * without specific prior written permission. |
52 | * |
53 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
54 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
55 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
56 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
57 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
58 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
59 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
60 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
61 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
62 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
63 | * SUCH DAMAGE. |
64 | */ |
65 | |
66 | /* |
67 | * VFS extended attribute support. |
68 | */ |
69 | |
70 | #include <sys/cdefs.h> |
71 | __KERNEL_RCSID(0, "$NetBSD: vfs_xattr.c,v 1.33 2014/09/05 09:20:59 matt Exp $" ); |
72 | |
73 | #include <sys/param.h> |
74 | #include <sys/systm.h> |
75 | #include <sys/namei.h> |
76 | #include <sys/filedesc.h> |
77 | #include <sys/kernel.h> |
78 | #include <sys/file.h> |
79 | #include <sys/vnode.h> |
80 | #include <sys/mount.h> |
81 | #include <sys/proc.h> |
82 | #include <sys/uio.h> |
83 | #include <sys/extattr.h> |
84 | #include <sys/xattr.h> |
85 | #include <sys/sysctl.h> |
86 | #include <sys/syscallargs.h> |
87 | #include <sys/kauth.h> |
88 | #include <sys/ktrace.h> |
89 | |
90 | #include <miscfs/genfs/genfs.h> |
91 | |
92 | /* |
93 | * Credential check based on process requesting service, and per-attribute |
94 | * permissions. |
95 | * |
96 | * NOTE: Vnode must be locked. |
97 | */ |
98 | int |
99 | extattr_check_cred(struct vnode *vp, const char *attr, kauth_cred_t cred, |
100 | int access) |
101 | { |
102 | |
103 | if (cred == NOCRED) |
104 | return (0); |
105 | |
106 | return kauth_authorize_vnode(cred, kauth_extattr_action(access), vp, |
107 | NULL, genfs_can_extattr(cred, access, vp, attr)); |
108 | } |
109 | |
110 | /* |
111 | * Default vfs_extattrctl routine for file systems that do not support |
112 | * it. |
113 | */ |
114 | /*ARGSUSED*/ |
115 | int |
116 | vfs_stdextattrctl(struct mount *mp, int cmt, struct vnode *vp, |
117 | int attrnamespace, const char *attrname) |
118 | { |
119 | |
120 | if (vp != NULL) |
121 | VOP_UNLOCK(vp); |
122 | return (EOPNOTSUPP); |
123 | } |
124 | |
125 | /* |
126 | * Push extended attribute configuration information into the file |
127 | * system. |
128 | * |
129 | * NOTE: Not all file systems that support extended attributes will |
130 | * require the use of this system call. |
131 | */ |
132 | int |
133 | sys_extattrctl(struct lwp *l, const struct sys_extattrctl_args *uap, register_t *retval) |
134 | { |
135 | /* { |
136 | syscallarg(const char *) path; |
137 | syscallarg(int) cmd; |
138 | syscallarg(const char *) filename; |
139 | syscallarg(int) attrnamespace; |
140 | syscallarg(const char *) attrname; |
141 | } */ |
142 | struct vnode *path_vp, *file_vp; |
143 | struct pathbuf *file_pb; |
144 | struct nameidata file_nd; |
145 | char attrname[EXTATTR_MAXNAMELEN]; |
146 | int error; |
147 | |
148 | if (SCARG(uap, attrname) != NULL) { |
149 | error = copyinstr(SCARG(uap, attrname), attrname, |
150 | sizeof(attrname), NULL); |
151 | if (error) |
152 | return (error); |
153 | } |
154 | |
155 | error = namei_simple_user(SCARG(uap, path), |
156 | NSM_FOLLOW_NOEMULROOT, &path_vp); |
157 | if (error) { |
158 | return (error); |
159 | } |
160 | |
161 | file_vp = NULL; |
162 | if (SCARG(uap, filename) != NULL) { |
163 | error = pathbuf_copyin(SCARG(uap, filename), &file_pb); |
164 | if (error) { |
165 | vrele(path_vp); |
166 | return (error); |
167 | } |
168 | NDINIT(&file_nd, LOOKUP, FOLLOW | LOCKLEAF, file_pb); |
169 | error = namei(&file_nd); |
170 | if (error) { |
171 | pathbuf_destroy(file_pb); |
172 | vrele(path_vp); |
173 | return (error); |
174 | } |
175 | file_vp = file_nd.ni_vp; |
176 | pathbuf_destroy(file_pb); |
177 | } |
178 | |
179 | error = VFS_EXTATTRCTL(path_vp->v_mount, SCARG(uap, cmd), file_vp, |
180 | SCARG(uap, attrnamespace), |
181 | SCARG(uap, attrname) != NULL ? attrname : NULL); |
182 | |
183 | if (file_vp != NULL) |
184 | vrele(file_vp); |
185 | vrele(path_vp); |
186 | |
187 | return (error); |
188 | } |
189 | |
190 | /***************************************************************************** |
191 | * Internal routines to manipulate file system extended attributes: |
192 | * - set |
193 | * - get |
194 | * - delete |
195 | * - list |
196 | *****************************************************************************/ |
197 | |
198 | /* |
199 | * extattr_set_vp: |
200 | * |
201 | * Set a named extended attribute on a file or directory. |
202 | */ |
203 | static int |
204 | extattr_set_vp(struct vnode *vp, int attrnamespace, const char *attrname, |
205 | const void *data, size_t nbytes, struct lwp *l, register_t *retval, |
206 | int flag) |
207 | { |
208 | struct uio auio; |
209 | struct iovec aiov; |
210 | ssize_t cnt; |
211 | int error; |
212 | |
213 | vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); |
214 | |
215 | if (flag) { |
216 | size_t attrlen; |
217 | |
218 | error = VOP_GETEXTATTR(vp, attrnamespace, attrname, NULL, |
219 | &attrlen, l->l_cred); |
220 | |
221 | switch (error) { |
222 | case ENODATA: |
223 | if (flag & XATTR_REPLACE) |
224 | goto done; |
225 | break; |
226 | case 0: |
227 | if (flag & XATTR_CREATE) { |
228 | error = EEXIST; |
229 | goto done; |
230 | } |
231 | break; |
232 | default: |
233 | goto done; |
234 | break; |
235 | } |
236 | } |
237 | |
238 | aiov.iov_base = __UNCONST(data); /* XXXUNCONST kills const */ |
239 | aiov.iov_len = nbytes; |
240 | auio.uio_iov = &aiov; |
241 | auio.uio_iovcnt = 1; |
242 | auio.uio_offset = 0; |
243 | if (nbytes > INT_MAX) { |
244 | error = EINVAL; |
245 | goto done; |
246 | } |
247 | auio.uio_resid = nbytes; |
248 | auio.uio_rw = UIO_WRITE; |
249 | KASSERT(l == curlwp); |
250 | auio.uio_vmspace = l->l_proc->p_vmspace; |
251 | cnt = nbytes; |
252 | |
253 | ktrkuser("xattr-name" , (void *)__UNCONST(attrname), strlen(attrname)); |
254 | ktrkuser("xattr-val" , __UNCONST(data), nbytes); |
255 | |
256 | error = VOP_SETEXTATTR(vp, attrnamespace, attrname, &auio, l->l_cred); |
257 | cnt -= auio.uio_resid; |
258 | retval[0] = cnt; |
259 | |
260 | done: |
261 | VOP_UNLOCK(vp); |
262 | return (error); |
263 | } |
264 | |
265 | /* |
266 | * extattr_get_vp: |
267 | * |
268 | * Get a named extended attribute on a file or directory. |
269 | */ |
270 | static int |
271 | extattr_get_vp(struct vnode *vp, int attrnamespace, const char *attrname, |
272 | void *data, size_t nbytes, struct lwp *l, register_t *retval) |
273 | { |
274 | struct uio auio, *auiop; |
275 | struct iovec aiov; |
276 | ssize_t cnt; |
277 | size_t size, *sizep; |
278 | int error; |
279 | |
280 | vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); |
281 | |
282 | /* |
283 | * Slightly unusual semantics: if the user provides a NULL data |
284 | * pointer, they don't want to receive the data, just the maximum |
285 | * read length. |
286 | */ |
287 | auiop = NULL; |
288 | sizep = NULL; |
289 | cnt = 0; |
290 | if (data != NULL) { |
291 | aiov.iov_base = data; |
292 | aiov.iov_len = nbytes; |
293 | auio.uio_iov = &aiov; |
294 | auio.uio_offset = 0; |
295 | if (nbytes > INT_MAX) { |
296 | error = EINVAL; |
297 | goto done; |
298 | } |
299 | auio.uio_resid = nbytes; |
300 | auio.uio_rw = UIO_READ; |
301 | KASSERT(l == curlwp); |
302 | auio.uio_vmspace = l->l_proc->p_vmspace; |
303 | auiop = &auio; |
304 | cnt = nbytes; |
305 | } else |
306 | sizep = &size; |
307 | |
308 | ktrkuser("xattr-name" , (void *)__UNCONST(attrname), strlen(attrname)); |
309 | |
310 | error = VOP_GETEXTATTR(vp, attrnamespace, attrname, auiop, sizep, |
311 | l->l_cred); |
312 | |
313 | if (auiop != NULL) { |
314 | cnt -= auio.uio_resid; |
315 | retval[0] = cnt; |
316 | |
317 | ktrkuser("xattr-val" , data, cnt); |
318 | } else |
319 | retval[0] = size; |
320 | |
321 | done: |
322 | VOP_UNLOCK(vp); |
323 | return (error); |
324 | } |
325 | |
326 | /* |
327 | * extattr_delete_vp: |
328 | * |
329 | * Delete a named extended attribute on a file or directory. |
330 | */ |
331 | static int |
332 | extattr_delete_vp(struct vnode *vp, int attrnamespace, const char *attrname, |
333 | struct lwp *l) |
334 | { |
335 | int error; |
336 | |
337 | vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); |
338 | |
339 | ktrkuser("xattr-name" , (void *)__UNCONST(attrname), strlen(attrname)); |
340 | |
341 | error = VOP_DELETEEXTATTR(vp, attrnamespace, attrname, l->l_cred); |
342 | if (error == EOPNOTSUPP) |
343 | error = VOP_SETEXTATTR(vp, attrnamespace, attrname, NULL, |
344 | l->l_cred); |
345 | |
346 | VOP_UNLOCK(vp); |
347 | return (error); |
348 | } |
349 | |
350 | /* |
351 | * extattr_list_vp: |
352 | * |
353 | * Retrieve a list of extended attributes on a file or directory. |
354 | */ |
355 | static int |
356 | extattr_list_vp(struct vnode *vp, int attrnamespace, void *data, size_t nbytes, |
357 | int flag, struct lwp *l, register_t *retval) |
358 | { |
359 | struct uio auio, *auiop; |
360 | size_t size, *sizep; |
361 | struct iovec aiov; |
362 | ssize_t cnt; |
363 | int error; |
364 | |
365 | vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); |
366 | |
367 | auiop = NULL; |
368 | sizep = NULL; |
369 | cnt = 0; |
370 | if (data != NULL) { |
371 | aiov.iov_base = data; |
372 | aiov.iov_len = nbytes; |
373 | auio.uio_iov = &aiov; |
374 | auio.uio_offset = 0; |
375 | if (nbytes > INT_MAX) { |
376 | error = EINVAL; |
377 | goto done; |
378 | } |
379 | auio.uio_resid = nbytes; |
380 | auio.uio_rw = UIO_READ; |
381 | KASSERT(l == curlwp); |
382 | auio.uio_vmspace = l->l_proc->p_vmspace; |
383 | auiop = &auio; |
384 | cnt = nbytes; |
385 | } else |
386 | sizep = &size; |
387 | |
388 | error = VOP_LISTEXTATTR(vp, attrnamespace, auiop, sizep, |
389 | flag, l->l_cred); |
390 | |
391 | if (auiop != NULL) { |
392 | cnt -= auio.uio_resid; |
393 | retval[0] = cnt; |
394 | |
395 | ktrkuser("xattr-list" , data, cnt); |
396 | } else |
397 | retval[0] = size; |
398 | |
399 | done: |
400 | VOP_UNLOCK(vp); |
401 | return (error); |
402 | } |
403 | |
404 | /***************************************************************************** |
405 | * BSD <sys/extattr.h> API for file system extended attributes |
406 | *****************************************************************************/ |
407 | |
408 | int |
409 | sys_extattr_set_fd(struct lwp *l, const struct sys_extattr_set_fd_args *uap, register_t *retval) |
410 | { |
411 | /* { |
412 | syscallarg(int) fd; |
413 | syscallarg(int) attrnamespace; |
414 | syscallarg(const char *) attrname; |
415 | syscallarg(const void *) data; |
416 | syscallarg(size_t) nbytes; |
417 | } */ |
418 | struct file *fp; |
419 | struct vnode *vp; |
420 | char attrname[EXTATTR_MAXNAMELEN]; |
421 | int error; |
422 | |
423 | error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname), |
424 | NULL); |
425 | if (error) |
426 | return (error); |
427 | |
428 | error = fd_getvnode(SCARG(uap, fd), &fp); |
429 | if (error) |
430 | return (error); |
431 | vp = fp->f_vnode; |
432 | |
433 | error = extattr_set_vp(vp, SCARG(uap, attrnamespace), attrname, |
434 | SCARG(uap, data), SCARG(uap, nbytes), l, retval, 0); |
435 | |
436 | fd_putfile(SCARG(uap, fd)); |
437 | return (error); |
438 | } |
439 | |
440 | int |
441 | sys_extattr_set_file(struct lwp *l, const struct sys_extattr_set_file_args *uap, register_t *retval) |
442 | { |
443 | /* { |
444 | syscallarg(const char *) path; |
445 | syscallarg(int) attrnamespace; |
446 | syscallarg(const char *) attrname; |
447 | syscallarg(const void *) data; |
448 | syscallarg(size_t) nbytes; |
449 | } */ |
450 | struct vnode *vp; |
451 | char attrname[EXTATTR_MAXNAMELEN]; |
452 | int error; |
453 | |
454 | error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname), |
455 | NULL); |
456 | if (error) |
457 | return (error); |
458 | |
459 | error = namei_simple_user(SCARG(uap, path), |
460 | NSM_FOLLOW_NOEMULROOT, &vp); |
461 | if (error) |
462 | return (error); |
463 | |
464 | error = extattr_set_vp(vp, SCARG(uap, attrnamespace), attrname, |
465 | SCARG(uap, data), SCARG(uap, nbytes), l, retval, 0); |
466 | |
467 | vrele(vp); |
468 | return (error); |
469 | } |
470 | |
471 | int |
472 | sys_extattr_set_link(struct lwp *l, const struct sys_extattr_set_link_args *uap, register_t *retval) |
473 | { |
474 | /* { |
475 | syscallarg(const char *) path; |
476 | syscallarg(int) attrnamespace; |
477 | syscallarg(const char *) attrname; |
478 | syscallarg(const void *) data; |
479 | syscallarg(size_t) nbytes; |
480 | } */ |
481 | struct vnode *vp; |
482 | char attrname[EXTATTR_MAXNAMELEN]; |
483 | int error; |
484 | |
485 | error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname), |
486 | NULL); |
487 | if (error) |
488 | return (error); |
489 | |
490 | error = namei_simple_user(SCARG(uap, path), |
491 | NSM_NOFOLLOW_NOEMULROOT, &vp); |
492 | if (error) |
493 | return (error); |
494 | |
495 | error = extattr_set_vp(vp, SCARG(uap, attrnamespace), attrname, |
496 | SCARG(uap, data), SCARG(uap, nbytes), l, retval, 0); |
497 | |
498 | vrele(vp); |
499 | return (error); |
500 | } |
501 | |
502 | int |
503 | sys_extattr_get_fd(struct lwp *l, const struct sys_extattr_get_fd_args *uap, register_t *retval) |
504 | { |
505 | /* { |
506 | syscallarg(int) fd; |
507 | syscallarg(int) attrnamespace; |
508 | syscallarg(const char *) attrname; |
509 | syscallarg(void *) data; |
510 | syscallarg(size_t) nbytes; |
511 | } */ |
512 | struct file *fp; |
513 | struct vnode *vp; |
514 | char attrname[EXTATTR_MAXNAMELEN]; |
515 | int error; |
516 | |
517 | error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname), |
518 | NULL); |
519 | if (error) |
520 | return (error); |
521 | |
522 | error = fd_getvnode(SCARG(uap, fd), &fp); |
523 | if (error) |
524 | return (error); |
525 | vp = fp->f_vnode; |
526 | |
527 | error = extattr_get_vp(vp, SCARG(uap, attrnamespace), attrname, |
528 | SCARG(uap, data), SCARG(uap, nbytes), l, retval); |
529 | |
530 | fd_putfile(SCARG(uap, fd)); |
531 | return (error); |
532 | } |
533 | |
534 | int |
535 | sys_extattr_get_file(struct lwp *l, const struct sys_extattr_get_file_args *uap, register_t *retval) |
536 | { |
537 | /* { |
538 | syscallarg(const char *) path; |
539 | syscallarg(int) attrnamespace; |
540 | syscallarg(const char *) attrname; |
541 | syscallarg(void *) data; |
542 | syscallarg(size_t) nbytes; |
543 | } */ |
544 | struct vnode *vp; |
545 | char attrname[EXTATTR_MAXNAMELEN]; |
546 | int error; |
547 | |
548 | error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname), |
549 | NULL); |
550 | if (error) |
551 | return (error); |
552 | |
553 | error = namei_simple_user(SCARG(uap, path), |
554 | NSM_FOLLOW_NOEMULROOT, &vp); |
555 | if (error) |
556 | return (error); |
557 | |
558 | error = extattr_get_vp(vp, SCARG(uap, attrnamespace), attrname, |
559 | SCARG(uap, data), SCARG(uap, nbytes), l, retval); |
560 | |
561 | vrele(vp); |
562 | return (error); |
563 | } |
564 | |
565 | int |
566 | sys_extattr_get_link(struct lwp *l, const struct sys_extattr_get_link_args *uap, register_t *retval) |
567 | { |
568 | /* { |
569 | syscallarg(const char *) path; |
570 | syscallarg(int) attrnamespace; |
571 | syscallarg(const char *) attrname; |
572 | syscallarg(void *) data; |
573 | syscallarg(size_t) nbytes; |
574 | } */ |
575 | struct vnode *vp; |
576 | char attrname[EXTATTR_MAXNAMELEN]; |
577 | int error; |
578 | |
579 | error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname), |
580 | NULL); |
581 | if (error) |
582 | return (error); |
583 | |
584 | error = namei_simple_user(SCARG(uap, path), |
585 | NSM_NOFOLLOW_NOEMULROOT, &vp); |
586 | if (error) |
587 | return (error); |
588 | |
589 | error = extattr_get_vp(vp, SCARG(uap, attrnamespace), attrname, |
590 | SCARG(uap, data), SCARG(uap, nbytes), l, retval); |
591 | |
592 | vrele(vp); |
593 | return (error); |
594 | } |
595 | |
596 | int |
597 | sys_extattr_delete_fd(struct lwp *l, const struct sys_extattr_delete_fd_args *uap, register_t *retval) |
598 | { |
599 | /* { |
600 | syscallarg(int) fd; |
601 | syscallarg(int) attrnamespace; |
602 | syscallarg(const char *) attrname; |
603 | } */ |
604 | struct file *fp; |
605 | struct vnode *vp; |
606 | char attrname[EXTATTR_MAXNAMELEN]; |
607 | int error; |
608 | |
609 | error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname), |
610 | NULL); |
611 | if (error) |
612 | return (error); |
613 | |
614 | error = fd_getvnode(SCARG(uap, fd), &fp); |
615 | if (error) |
616 | return (error); |
617 | vp = fp->f_vnode; |
618 | |
619 | error = extattr_delete_vp(vp, SCARG(uap, attrnamespace), attrname, l); |
620 | |
621 | fd_putfile(SCARG(uap, fd)); |
622 | return (error); |
623 | } |
624 | |
625 | int |
626 | sys_extattr_delete_file(struct lwp *l, const struct sys_extattr_delete_file_args *uap, register_t *retval) |
627 | { |
628 | /* { |
629 | syscallarg(const char *) path; |
630 | syscallarg(int) attrnamespace; |
631 | syscallarg(const char *) attrname; |
632 | } */ |
633 | struct vnode *vp; |
634 | char attrname[EXTATTR_MAXNAMELEN]; |
635 | int error; |
636 | |
637 | error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname), |
638 | NULL); |
639 | if (error) |
640 | return (error); |
641 | |
642 | error = namei_simple_user(SCARG(uap, path), |
643 | NSM_FOLLOW_NOEMULROOT, &vp); |
644 | if (error) |
645 | return (error); |
646 | |
647 | error = extattr_delete_vp(vp, SCARG(uap, attrnamespace), attrname, l); |
648 | |
649 | vrele(vp); |
650 | return (error); |
651 | } |
652 | |
653 | int |
654 | sys_extattr_delete_link(struct lwp *l, const struct sys_extattr_delete_link_args *uap, register_t *retval) |
655 | { |
656 | /* { |
657 | syscallarg(const char *) path; |
658 | syscallarg(int) attrnamespace; |
659 | syscallarg(const char *) attrname; |
660 | } */ |
661 | struct vnode *vp; |
662 | char attrname[EXTATTR_MAXNAMELEN]; |
663 | int error; |
664 | |
665 | error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname), |
666 | NULL); |
667 | if (error) |
668 | return (error); |
669 | |
670 | error = namei_simple_user(SCARG(uap, path), |
671 | NSM_NOFOLLOW_NOEMULROOT, &vp); |
672 | if (error) |
673 | return (error); |
674 | |
675 | error = extattr_delete_vp(vp, SCARG(uap, attrnamespace), attrname, l); |
676 | |
677 | vrele(vp); |
678 | return (error); |
679 | } |
680 | |
681 | int |
682 | sys_extattr_list_fd(struct lwp *l, const struct sys_extattr_list_fd_args *uap, register_t *retval) |
683 | { |
684 | /* { |
685 | syscallarg(int) fd; |
686 | syscallarg(int) attrnamespace; |
687 | syscallarg(void *) data; |
688 | syscallarg(size_t) nbytes; |
689 | } */ |
690 | struct file *fp; |
691 | struct vnode *vp; |
692 | int error; |
693 | |
694 | error = fd_getvnode(SCARG(uap, fd), &fp); |
695 | if (error) |
696 | return (error); |
697 | vp = fp->f_vnode; |
698 | |
699 | error = extattr_list_vp(vp, SCARG(uap, attrnamespace), |
700 | SCARG(uap, data), SCARG(uap, nbytes), |
701 | EXTATTR_LIST_LENPREFIX, l, retval); |
702 | |
703 | fd_putfile(SCARG(uap, fd)); |
704 | return (error); |
705 | } |
706 | |
707 | int |
708 | sys_extattr_list_file(struct lwp *l, const struct sys_extattr_list_file_args *uap, register_t *retval) |
709 | { |
710 | /* { |
711 | syscallarg(const char *) path; |
712 | syscallarg(int) attrnamespace; |
713 | syscallarg(void *) data; |
714 | syscallarg(size_t) nbytes; |
715 | } */ |
716 | struct vnode *vp; |
717 | int error; |
718 | |
719 | error = namei_simple_user(SCARG(uap, path), |
720 | NSM_FOLLOW_NOEMULROOT, &vp); |
721 | if (error) |
722 | return (error); |
723 | |
724 | error = extattr_list_vp(vp, SCARG(uap, attrnamespace), |
725 | SCARG(uap, data), SCARG(uap, nbytes), |
726 | EXTATTR_LIST_LENPREFIX, l, retval); |
727 | |
728 | vrele(vp); |
729 | return (error); |
730 | } |
731 | |
732 | int |
733 | sys_extattr_list_link(struct lwp *l, const struct sys_extattr_list_link_args *uap, register_t *retval) |
734 | { |
735 | /* { |
736 | syscallarg(const char *) path; |
737 | syscallarg(int) attrnamespace; |
738 | syscallarg(void *) data; |
739 | syscallarg(size_t) nbytes; |
740 | } */ |
741 | struct vnode *vp; |
742 | int error; |
743 | |
744 | error = namei_simple_user(SCARG(uap, path), |
745 | NSM_NOFOLLOW_NOEMULROOT, &vp); |
746 | if (error) |
747 | return (error); |
748 | |
749 | error = extattr_list_vp(vp, SCARG(uap, attrnamespace), |
750 | SCARG(uap, data), SCARG(uap, nbytes), |
751 | EXTATTR_LIST_LENPREFIX, l, retval); |
752 | |
753 | vrele(vp); |
754 | return (error); |
755 | } |
756 | |
757 | /***************************************************************************** |
758 | * Linux-compatible <sys/xattr.h> API for file system extended attributes |
759 | *****************************************************************************/ |
760 | |
761 | #define MATCH_NS(ns, key) (strncmp(ns, key, sizeof(ns) - 1) == 0) |
762 | static int |
763 | xattr_native(const char *key) { |
764 | if (MATCH_NS("system." , key)) |
765 | return EXTATTR_NAMESPACE_SYSTEM; |
766 | else if (MATCH_NS("user." , key)) |
767 | return EXTATTR_NAMESPACE_USER; |
768 | else if (MATCH_NS("security." , key)) |
769 | return EXTATTR_NAMESPACE_SYSTEM; |
770 | else if (MATCH_NS("trusted." , key)) |
771 | return EXTATTR_NAMESPACE_SYSTEM; |
772 | else |
773 | return EXTATTR_NAMESPACE_USER; |
774 | |
775 | } |
776 | #undef MATCH_NS |
777 | |
778 | #define XATTR_ERRNO(e) ((e) == EOPNOTSUPP ? ENOTSUP : (e)) |
779 | |
780 | int |
781 | sys_setxattr(struct lwp *l, const struct sys_setxattr_args *uap, register_t *retval) |
782 | { |
783 | /* { |
784 | syscallarg(const char *) path; |
785 | syscallarg(const char *) name; |
786 | syscallarg(void *) value; |
787 | syscallarg(size_t) size; |
788 | syscallarg(int) flags; |
789 | } */ |
790 | struct vnode *vp; |
791 | char attrname[XATTR_NAME_MAX]; |
792 | int attrnamespace; |
793 | register_t attrlen; |
794 | int error; |
795 | |
796 | error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname), |
797 | NULL); |
798 | if (error) |
799 | goto out; |
800 | |
801 | error = namei_simple_user(SCARG(uap, path), |
802 | NSM_FOLLOW_NOEMULROOT, &vp); |
803 | if (error) |
804 | goto out; |
805 | |
806 | attrnamespace = xattr_native(attrname); |
807 | |
808 | error = extattr_set_vp(vp, attrnamespace, |
809 | attrname, SCARG(uap, value), SCARG(uap, size), l, |
810 | &attrlen, SCARG(uap, flags)); |
811 | |
812 | vrele(vp); |
813 | out: |
814 | *retval = (error == 0) ? 0 : -1; |
815 | return (XATTR_ERRNO(error)); |
816 | } |
817 | |
818 | int |
819 | sys_lsetxattr(struct lwp *l, const struct sys_lsetxattr_args *uap, register_t *retval) |
820 | { |
821 | /* { |
822 | syscallarg(const char *) path; |
823 | syscallarg(const char *) name; |
824 | syscallarg(void *) value; |
825 | syscallarg(size_t) size; |
826 | syscallarg(int) flags; |
827 | } */ |
828 | struct vnode *vp; |
829 | char attrname[XATTR_NAME_MAX]; |
830 | int attrnamespace; |
831 | register_t attrlen; |
832 | int error; |
833 | |
834 | error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname), |
835 | NULL); |
836 | if (error) |
837 | goto out; |
838 | |
839 | error = namei_simple_user(SCARG(uap, path), |
840 | NSM_NOFOLLOW_NOEMULROOT, &vp); |
841 | if (error) |
842 | goto out; |
843 | |
844 | attrnamespace = xattr_native(attrname); |
845 | |
846 | error = extattr_set_vp(vp, attrnamespace, |
847 | attrname, SCARG(uap, value), SCARG(uap, size), l, |
848 | &attrlen, SCARG(uap, flags)); |
849 | |
850 | vrele(vp); |
851 | out: |
852 | *retval = (error == 0) ? 0 : -1; |
853 | return (XATTR_ERRNO(error)); |
854 | } |
855 | |
856 | int |
857 | sys_fsetxattr(struct lwp *l, const struct sys_fsetxattr_args *uap, register_t *retval) |
858 | { |
859 | /* { |
860 | syscallarg(int) fd; |
861 | syscallarg(const char *) name; |
862 | syscallarg(void *) value; |
863 | syscallarg(size_t) size; |
864 | syscallarg(int) flags; |
865 | } */ |
866 | struct file *fp; |
867 | struct vnode *vp; |
868 | char attrname[XATTR_NAME_MAX]; |
869 | int attrnamespace; |
870 | register_t attrlen; |
871 | int error; |
872 | |
873 | error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname), |
874 | NULL); |
875 | if (error) |
876 | goto out; |
877 | |
878 | error = fd_getvnode(SCARG(uap, fd), &fp); |
879 | if (error) |
880 | goto out; |
881 | vp = fp->f_vnode; |
882 | |
883 | attrnamespace = xattr_native(attrname); |
884 | |
885 | error = extattr_set_vp(vp, attrnamespace, |
886 | attrname, SCARG(uap, value), SCARG(uap, size), l, |
887 | &attrlen, SCARG(uap, flags)); |
888 | |
889 | fd_putfile(SCARG(uap, fd)); |
890 | out: |
891 | *retval = (error == 0) ? 0 : -1; |
892 | return (XATTR_ERRNO(error)); |
893 | } |
894 | |
895 | int |
896 | sys_getxattr(struct lwp *l, const struct sys_getxattr_args *uap, register_t *retval) |
897 | { |
898 | /* { |
899 | syscallarg(const char *) path; |
900 | syscallarg(const char *) name; |
901 | syscallarg(void *) value; |
902 | syscallarg(size_t) size; |
903 | } */ |
904 | struct vnode *vp; |
905 | char attrname[XATTR_NAME_MAX]; |
906 | int attrnamespace; |
907 | int error; |
908 | |
909 | error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname), |
910 | NULL); |
911 | if (error) |
912 | return (error); |
913 | |
914 | error = namei_simple_user(SCARG(uap, path), |
915 | NSM_FOLLOW_NOEMULROOT, &vp); |
916 | if (error) |
917 | return (error); |
918 | |
919 | attrnamespace = xattr_native(attrname); |
920 | |
921 | error = extattr_get_vp(vp, attrnamespace, |
922 | attrname, SCARG(uap, value), SCARG(uap, size), l, retval); |
923 | |
924 | vrele(vp); |
925 | return (XATTR_ERRNO(error)); |
926 | } |
927 | |
928 | int |
929 | sys_lgetxattr(struct lwp *l, const struct sys_lgetxattr_args *uap, register_t *retval) |
930 | { |
931 | /* { |
932 | syscallarg(const char *) path; |
933 | syscallarg(const char *) name; |
934 | syscallarg(void *) value; |
935 | syscallarg(size_t) size; |
936 | } */ |
937 | struct vnode *vp; |
938 | char attrname[XATTR_NAME_MAX]; |
939 | int attrnamespace; |
940 | int error; |
941 | |
942 | error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname), |
943 | NULL); |
944 | if (error) |
945 | return (error); |
946 | |
947 | error = namei_simple_user(SCARG(uap, path), |
948 | NSM_NOFOLLOW_NOEMULROOT, &vp); |
949 | if (error) |
950 | return (error); |
951 | |
952 | attrnamespace = xattr_native(attrname); |
953 | |
954 | error = extattr_get_vp(vp, attrnamespace, |
955 | attrname, SCARG(uap, value), SCARG(uap, size), l, retval); |
956 | |
957 | vrele(vp); |
958 | return (XATTR_ERRNO(error)); |
959 | } |
960 | |
961 | int |
962 | sys_fgetxattr(struct lwp *l, const struct sys_fgetxattr_args *uap, register_t *retval) |
963 | { |
964 | /* { |
965 | syscallarg(int) fd; |
966 | syscallarg(const char *) name; |
967 | syscallarg(void *) value; |
968 | syscallarg(size_t) size; |
969 | } */ |
970 | struct file *fp; |
971 | struct vnode *vp; |
972 | char attrname[XATTR_NAME_MAX]; |
973 | int attrnamespace; |
974 | int error; |
975 | |
976 | error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname), |
977 | NULL); |
978 | if (error) |
979 | return (error); |
980 | |
981 | error = fd_getvnode(SCARG(uap, fd), &fp); |
982 | if (error) |
983 | return (error); |
984 | vp = fp->f_vnode; |
985 | |
986 | attrnamespace = xattr_native(attrname); |
987 | |
988 | error = extattr_get_vp(vp, attrnamespace, |
989 | attrname, SCARG(uap, value), SCARG(uap, size), l, retval); |
990 | |
991 | fd_putfile(SCARG(uap, fd)); |
992 | return (XATTR_ERRNO(error)); |
993 | } |
994 | |
995 | int |
996 | sys_listxattr(struct lwp *l, const struct sys_listxattr_args *uap, register_t *retval) |
997 | { |
998 | /* { |
999 | syscallarg(const char *) path; |
1000 | syscallarg(char *) list; |
1001 | syscallarg(size_t) size; |
1002 | } */ |
1003 | struct vnode *vp; |
1004 | char *list; |
1005 | size_t size; |
1006 | register_t listsize_usr, listsize_sys; |
1007 | int error; |
1008 | |
1009 | error = namei_simple_user(SCARG(uap, path), |
1010 | NSM_FOLLOW_NOEMULROOT, &vp); |
1011 | if (error) |
1012 | return (error); |
1013 | |
1014 | list = SCARG(uap, list); |
1015 | size = SCARG(uap, size); |
1016 | |
1017 | error = extattr_list_vp(vp, EXTATTR_NAMESPACE_USER, |
1018 | list, size, 0, l, &listsize_usr); |
1019 | if (error) |
1020 | goto out; |
1021 | |
1022 | if (list) |
1023 | list += listsize_usr; |
1024 | if (size) |
1025 | size -= listsize_usr; |
1026 | |
1027 | error = extattr_list_vp(vp, EXTATTR_NAMESPACE_SYSTEM, |
1028 | list, size, 0, l, &listsize_sys); |
1029 | switch (error) { |
1030 | case EPERM: |
1031 | error = 0; /* Ignore and just skip system EA */ |
1032 | listsize_sys = 0; |
1033 | break; |
1034 | case 0: |
1035 | break; |
1036 | default: |
1037 | goto out; |
1038 | break; |
1039 | } |
1040 | |
1041 | *retval = listsize_usr + listsize_sys; |
1042 | |
1043 | out: |
1044 | vrele(vp); |
1045 | return (XATTR_ERRNO(error)); |
1046 | } |
1047 | |
1048 | int |
1049 | sys_llistxattr(struct lwp *l, const struct sys_llistxattr_args *uap, register_t *retval) |
1050 | { |
1051 | /* { |
1052 | syscallarg(const char *) path; |
1053 | syscallarg(char *) list; |
1054 | syscallarg(size_t) size; |
1055 | } */ |
1056 | struct vnode *vp; |
1057 | char *list; |
1058 | size_t size; |
1059 | register_t listsize_usr, listsize_sys; |
1060 | int error; |
1061 | |
1062 | error = namei_simple_user(SCARG(uap, path), |
1063 | NSM_NOFOLLOW_NOEMULROOT, &vp); |
1064 | if (error) |
1065 | return (error); |
1066 | |
1067 | list = SCARG(uap, list); |
1068 | size = SCARG(uap, size); |
1069 | |
1070 | error = extattr_list_vp(vp, EXTATTR_NAMESPACE_USER, |
1071 | list, size, 0, l, &listsize_usr); |
1072 | if (error) |
1073 | goto out; |
1074 | if (list) |
1075 | list += listsize_usr; |
1076 | if (size) |
1077 | size -= listsize_usr; |
1078 | |
1079 | error = extattr_list_vp(vp, EXTATTR_NAMESPACE_SYSTEM, |
1080 | list, size, 0, l, &listsize_sys); |
1081 | switch (error) { |
1082 | case EPERM: |
1083 | error = 0; /* Ignore and just skip system EA */ |
1084 | listsize_sys = 0; |
1085 | break; |
1086 | case 0: |
1087 | break; |
1088 | default: |
1089 | goto out; |
1090 | break; |
1091 | } |
1092 | |
1093 | *retval = listsize_usr + listsize_sys; |
1094 | out: |
1095 | vrele(vp); |
1096 | return (XATTR_ERRNO(error)); |
1097 | } |
1098 | |
1099 | int |
1100 | sys_flistxattr(struct lwp *l, const struct sys_flistxattr_args *uap, register_t *retval) |
1101 | { |
1102 | /* { |
1103 | syscallarg(int) fd; |
1104 | syscallarg(char *) list; |
1105 | syscallarg(size_t) size; |
1106 | } */ |
1107 | struct file *fp; |
1108 | struct vnode *vp; |
1109 | char *list; |
1110 | size_t size; |
1111 | register_t listsize_usr, listsize_sys; |
1112 | int error; |
1113 | |
1114 | error = fd_getvnode(SCARG(uap, fd), &fp); |
1115 | if (error) |
1116 | return (error); |
1117 | vp = fp->f_vnode; |
1118 | |
1119 | list = SCARG(uap, list); |
1120 | size = SCARG(uap, size); |
1121 | |
1122 | error = extattr_list_vp(vp, EXTATTR_NAMESPACE_USER, |
1123 | list, size, 0, l, &listsize_usr); |
1124 | if (error) |
1125 | goto out; |
1126 | |
1127 | if (list) |
1128 | list += listsize_usr; |
1129 | if (size) |
1130 | size -= listsize_usr; |
1131 | |
1132 | error = extattr_list_vp(vp, EXTATTR_NAMESPACE_SYSTEM, |
1133 | list, size, 0, l, &listsize_sys); |
1134 | switch (error) { |
1135 | case EPERM: |
1136 | error = 0; /* Ignore and just skip system EA */ |
1137 | listsize_sys = 0; |
1138 | break; |
1139 | case 0: |
1140 | break; |
1141 | default: |
1142 | goto out; |
1143 | break; |
1144 | } |
1145 | |
1146 | *retval = listsize_usr + listsize_sys; |
1147 | out: |
1148 | |
1149 | fd_putfile(SCARG(uap, fd)); |
1150 | return (XATTR_ERRNO(error)); |
1151 | } |
1152 | |
1153 | int |
1154 | sys_removexattr(struct lwp *l, const struct sys_removexattr_args *uap, register_t *retval) |
1155 | { |
1156 | /* { |
1157 | syscallarg(const char *) path; |
1158 | syscallarg(const char *) name; |
1159 | } */ |
1160 | struct vnode *vp; |
1161 | char attrname[XATTR_NAME_MAX]; |
1162 | int attrnamespace; |
1163 | int error; |
1164 | |
1165 | error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname), |
1166 | NULL); |
1167 | if (error) |
1168 | return (error); |
1169 | |
1170 | error = namei_simple_user(SCARG(uap, path), |
1171 | NSM_FOLLOW_NOEMULROOT, &vp); |
1172 | if (error) |
1173 | return (error); |
1174 | |
1175 | attrnamespace = xattr_native(attrname); |
1176 | |
1177 | error = extattr_delete_vp(vp, attrnamespace, attrname, l); |
1178 | |
1179 | vrele(vp); |
1180 | return (XATTR_ERRNO(error)); |
1181 | } |
1182 | |
1183 | int |
1184 | sys_lremovexattr(struct lwp *l, const struct sys_lremovexattr_args *uap, register_t *retval) |
1185 | { |
1186 | /* { |
1187 | syscallarg(const char *) path; |
1188 | syscallarg(const char *) name; |
1189 | } */ |
1190 | struct vnode *vp; |
1191 | char attrname[XATTR_NAME_MAX]; |
1192 | int attrnamespace; |
1193 | int error; |
1194 | |
1195 | error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname), |
1196 | NULL); |
1197 | if (error) |
1198 | return (error); |
1199 | |
1200 | error = namei_simple_user(SCARG(uap, path), |
1201 | NSM_NOFOLLOW_NOEMULROOT, &vp); |
1202 | if (error) |
1203 | return (error); |
1204 | |
1205 | attrnamespace = xattr_native(attrname); |
1206 | |
1207 | error = extattr_delete_vp(vp, attrnamespace, attrname, l); |
1208 | |
1209 | vrele(vp); |
1210 | return (XATTR_ERRNO(error)); |
1211 | } |
1212 | |
1213 | int |
1214 | sys_fremovexattr(struct lwp *l, const struct sys_fremovexattr_args *uap, register_t *retval) |
1215 | { |
1216 | /* { |
1217 | syscallarg(int) fd; |
1218 | syscallarg(const char *) name; |
1219 | } */ |
1220 | struct file *fp; |
1221 | struct vnode *vp; |
1222 | char attrname[XATTR_NAME_MAX]; |
1223 | int attrnamespace; |
1224 | int error; |
1225 | |
1226 | error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname), |
1227 | NULL); |
1228 | if (error) |
1229 | return (error); |
1230 | |
1231 | error = fd_getvnode(SCARG(uap, fd), &fp); |
1232 | if (error) |
1233 | return (error); |
1234 | vp = fp->f_vnode; |
1235 | |
1236 | attrnamespace = xattr_native(attrname); |
1237 | |
1238 | error = extattr_delete_vp(vp, attrnamespace, attrname, l); |
1239 | |
1240 | fd_putfile(SCARG(uap, fd)); |
1241 | return (XATTR_ERRNO(error)); |
1242 | } |
1243 | |