]> git.saurik.com Git - apple/xnu.git/blame - bsd/vfs/vfs_xattr.c
xnu-1699.22.81.tar.gz
[apple/xnu.git] / bsd / vfs / vfs_xattr.c
CommitLineData
91447636 1/*
6d2010ae 2 * Copyright (c) 2004-2010 Apple Inc. All rights reserved.
91447636 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
91447636 5 *
2d21ac55
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
8f6c56a5 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
91447636 27 */
2d21ac55
A
28/*
29 * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
30 * support for mandatory and extensible security protections. This notice
31 * is included in support of clause 2.2 (b) of the Apple Public License,
32 * Version 2.0.
33 */
34
91447636
A
35#include <sys/param.h>
36
37#include <sys/fcntl.h>
38#include <sys/fsevents.h>
39#include <sys/kernel.h>
40#include <sys/kauth.h>
41#include <sys/malloc.h>
2d21ac55 42#include <sys/mount_internal.h>
91447636
A
43#include <sys/namei.h>
44#include <sys/proc_internal.h>
45#include <sys/stat.h>
46#include <sys/uio.h>
47#include <sys/utfconv.h>
48#include <sys/vnode.h>
49#include <sys/vnode_internal.h>
91447636
A
50#include <sys/xattr.h>
51
4452a7af 52#include <libkern/OSByteOrder.h>
91447636
A
53#include <vm/vm_kern.h>
54
2d21ac55
A
55#if CONFIG_MACF
56#include <security/mac_framework.h>
57#endif
58
59
60#if NAMEDSTREAMS
61
91447636 62/*
b0d623f7 63 * We use %p to prevent loss of precision for pointers on varying architectures.
91447636 64 */
2d21ac55 65#define MAKE_SHADOW_NAME(VP, NAME) \
b0d623f7 66 snprintf((NAME), sizeof((NAME)), ".vfs_rsrc_stream_%p%08x%p", (void*)(VP), (VP)->v_id, (VP)->v_data);
2d21ac55 67
2d21ac55
A
68static int shadow_sequence;
69
70
71static int default_getnamedstream(vnode_t vp, vnode_t *svpp, const char *name, enum nsoperation op, vfs_context_t context);
72
73static int default_makenamedstream(vnode_t vp, vnode_t *svpp, const char *name, vfs_context_t context);
91447636 74
2d21ac55 75static int default_removenamedstream(vnode_t vp, const char *name, vfs_context_t context);
91447636 76
2d21ac55
A
77static int getshadowfile(vnode_t vp, vnode_t *svpp, int makestream, size_t *rsrcsize, int *creator, vfs_context_t context);
78
79static int get_shadow_dir(vnode_t *sdvpp, vfs_context_t context);
80
81#endif
82
83
84/*
85 * Default xattr support routines.
86 */
91447636
A
87
88static int default_listxattr(vnode_t vp, uio_t uio, size_t *size, int options,
89 vfs_context_t context);
90
91
92
93/*
94 * Retrieve the data of an extended attribute.
95 */
96int
97vn_getxattr(vnode_t vp, const char *name, uio_t uio, size_t *size,
98 int options, vfs_context_t context)
99{
100 int error;
101
102 if (!(vp->v_type == VREG || vp->v_type == VDIR || vp->v_type == VLNK)) {
103 return (EPERM);
104 }
2d21ac55
A
105#if NAMEDSTREAMS
106 /* getxattr calls are not allowed for streams. */
107 if (vp->v_flag & VISNAMEDSTREAM) {
108 error = EPERM;
91447636 109 goto out;
2d21ac55
A
110 }
111#endif
112 /*
113 * Non-kernel request need extra checks performed.
114 *
115 * The XATTR_NOSECURITY flag implies a kernel request.
116 */
117 if (!(options & XATTR_NOSECURITY)) {
118#if CONFIG_MACF
119 error = mac_vnode_check_getextattr(context, vp, name, uio);
120 if (error)
121 goto out;
122#endif /* MAC */
123 if ((error = xattr_validatename(name))) {
124 goto out;
125 }
126 if ((error = vnode_authorize(vp, NULL, KAUTH_VNODE_READ_EXTATTRIBUTES, context))) {
127 goto out;
128 }
129 /* The offset can only be non-zero for resource forks. */
130 if (uio != NULL && uio_offset(uio) != 0 &&
131 bcmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) != 0) {
132 error = EINVAL;
133 goto out;
134 }
135 }
91447636
A
136
137 /* The offset can only be non-zero for resource forks. */
138 if (uio != NULL && uio_offset(uio) != 0 &&
139 bcmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) != 0) {
140 error = EINVAL;
141 goto out;
142 }
143
144 error = VNOP_GETXATTR(vp, name, uio, size, options, context);
2d21ac55 145 if (error == ENOTSUP && !(options & XATTR_NODEFAULT)) {
91447636
A
146 /*
147 * A filesystem may keep some EAs natively and return ENOTSUP for others.
148 * SMB returns ENOTSUP for finderinfo and resource forks.
149 */
150 error = default_getxattr(vp, name, uio, size, options, context);
151 }
152out:
153 return (error);
154}
155
156/*
157 * Set the data of an extended attribute.
158 */
159int
160vn_setxattr(vnode_t vp, const char *name, uio_t uio, int options, vfs_context_t context)
161{
162 int error;
163
164 if (!(vp->v_type == VREG || vp->v_type == VDIR || vp->v_type == VLNK)) {
165 return (EPERM);
166 }
2d21ac55
A
167#if NAMEDSTREAMS
168 /* setxattr calls are not allowed for streams. */
169 if (vp->v_flag & VISNAMEDSTREAM) {
170 error = EPERM;
171 goto out;
172 }
173#endif
91447636
A
174 if ((options & (XATTR_REPLACE|XATTR_CREATE)) == (XATTR_REPLACE|XATTR_CREATE)) {
175 return (EINVAL);
176 }
177 if ((error = xattr_validatename(name))) {
178 return (error);
179 }
2d21ac55
A
180 if (!(options & XATTR_NOSECURITY)) {
181#if CONFIG_MACF
182 error = mac_vnode_check_setextattr(context, vp, name, uio);
183 if (error)
184 goto out;
185#endif /* MAC */
186 error = vnode_authorize(vp, NULL, KAUTH_VNODE_WRITE_EXTATTRIBUTES, context);
187 if (error)
188 goto out;
189 }
91447636
A
190 /* The offset can only be non-zero for resource forks. */
191 if (uio_offset(uio) != 0 &&
192 bcmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) != 0 ) {
193 error = EINVAL;
194 goto out;
195 }
196
197 error = VNOP_SETXATTR(vp, name, uio, options, context);
198#ifdef DUAL_EAS
199 /*
200 * An EJUSTRETURN is from a filesystem which keeps this xattr
201 * natively as well as in a dot-underscore file. In this case the
202 * EJUSTRETURN means the filesytem has done nothing, but identifies the
203 * EA as one which may be represented natively and/or in a DU, and
204 * since XATTR_CREATE or XATTR_REPLACE was specified, only up here in
205 * in vn_setxattr can we do the getxattrs needed to ascertain whether
206 * the XATTR_{CREATE,REPLACE} should yield an error.
207 */
208 if (error == EJUSTRETURN) {
209 int native = 0, dufile = 0;
210 size_t sz; /* not used */
211
212 native = VNOP_GETXATTR(vp, name, NULL, &sz, 0, context) ? 0 : 1;
213 dufile = default_getxattr(vp, name, NULL, &sz, 0, context) ? 0 : 1;
214 if (options & XATTR_CREATE && (native || dufile)) {
215 error = EEXIST;
216 goto out;
217 }
218 if (options & XATTR_REPLACE && !(native || dufile)) {
219 error = ENOATTR;
220 goto out;
221 }
222 /*
223 * Having determined no CREATE/REPLACE error should result, we
224 * zero those bits, so both backing stores get written to.
225 */
226 options &= ~(XATTR_CREATE | XATTR_REPLACE);
227 error = VNOP_SETXATTR(vp, name, uio, options, context);
228 /* the mainline path here is to have error==ENOTSUP ... */
229 }
230#endif /* DUAL_EAS */
2d21ac55 231 if (error == ENOTSUP && !(options & XATTR_NODEFAULT)) {
91447636
A
232 /*
233 * A filesystem may keep some EAs natively and return ENOTSUP for others.
234 * SMB returns ENOTSUP for finderinfo and resource forks.
235 */
236 error = default_setxattr(vp, name, uio, options, context);
237 }
2d21ac55
A
238#if CONFIG_MACF
239 if ((error == 0) && !(options & XATTR_NOSECURITY) &&
240 (vfs_flags(vnode_mount(vp)) & MNT_MULTILABEL))
241 mac_vnode_label_update_extattr(vnode_mount(vp), vp, name);
242#endif
91447636
A
243out:
244 return (error);
245}
246
247/*
248 * Remove an extended attribute.
249 */
250int
251vn_removexattr(vnode_t vp, const char * name, int options, vfs_context_t context)
252{
253 int error;
254
255 if (!(vp->v_type == VREG || vp->v_type == VDIR || vp->v_type == VLNK)) {
256 return (EPERM);
257 }
2d21ac55
A
258#if NAMEDSTREAMS
259 /* removexattr calls are not allowed for streams. */
260 if (vp->v_flag & VISNAMEDSTREAM) {
261 error = EPERM;
262 goto out;
263 }
264#endif
91447636
A
265 if ((error = xattr_validatename(name))) {
266 return (error);
267 }
2d21ac55
A
268 if (!(options & XATTR_NOSECURITY)) {
269#if CONFIG_MACF
270 error = mac_vnode_check_deleteextattr(context, vp, name);
271 if (error)
272 goto out;
273#endif /* MAC */
274 error = vnode_authorize(vp, NULL, KAUTH_VNODE_WRITE_EXTATTRIBUTES, context);
275 if (error)
276 goto out;
277 }
91447636 278 error = VNOP_REMOVEXATTR(vp, name, options, context);
2d21ac55 279 if (error == ENOTSUP && !(options & XATTR_NODEFAULT)) {
91447636
A
280 /*
281 * A filesystem may keep some EAs natively and return ENOTSUP for others.
282 * SMB returns ENOTSUP for finderinfo and resource forks.
283 */
284 error = default_removexattr(vp, name, options, context);
285#ifdef DUAL_EAS
286 } else if (error == EJUSTRETURN) {
287 /*
288 * EJUSTRETURN is from a filesystem which keeps this xattr natively as well
289 * as in a dot-underscore file. EJUSTRETURN means the filesytem did remove
290 * a native xattr, so failure to find it in a DU file during
291 * default_removexattr should not be considered an error.
292 */
293 error = default_removexattr(vp, name, options, context);
294 if (error == ENOATTR)
295 error = 0;
296#endif /* DUAL_EAS */
297 }
2d21ac55
A
298#if CONFIG_MACF
299 if ((error == 0) && !(options & XATTR_NOSECURITY) &&
300 (vfs_flags(vnode_mount(vp)) & MNT_MULTILABEL))
301 mac_vnode_label_update_extattr(vnode_mount(vp), vp, name);
302#endif
91447636
A
303out:
304 return (error);
305}
306
307/*
308 * Retrieve the list of extended attribute names.
309 */
310int
311vn_listxattr(vnode_t vp, uio_t uio, size_t *size, int options, vfs_context_t context)
312{
313 int error;
314
315 if (!(vp->v_type == VREG || vp->v_type == VDIR || vp->v_type == VLNK)) {
316 return (EPERM);
317 }
2d21ac55
A
318#if NAMEDSTREAMS
319 /* listxattr calls are not allowed for streams. */
320 if (vp->v_flag & VISNAMEDSTREAM) {
321 return (EPERM);
322 }
323#endif
324
325 if (!(options & XATTR_NOSECURITY)) {
326#if CONFIG_MACF
327 error = mac_vnode_check_listextattr(context, vp);
328 if (error)
329 goto out;
330#endif /* MAC */
331
332 error = vnode_authorize(vp, NULL, KAUTH_VNODE_READ_EXTATTRIBUTES, context);
333 if (error)
334 goto out;
335 }
91447636
A
336
337 error = VNOP_LISTXATTR(vp, uio, size, options, context);
2d21ac55 338 if (error == ENOTSUP && !(options & XATTR_NODEFAULT)) {
91447636
A
339 /*
340 * A filesystem may keep some but not all EAs natively, in which case
341 * the native EA names will have been uiomove-d out (or *size updated)
342 * and the default_listxattr here will finish the job. Note SMB takes
343 * advantage of this for its finder-info and resource forks.
344 */
345 error = default_listxattr(vp, uio, size, options, context);
346 }
347out:
348 return (error);
349}
350
351int
352xattr_validatename(const char *name)
353{
354 int namelen;
355
356 if (name == NULL || name[0] == '\0') {
357 return (EINVAL);
358 }
6601e61a
A
359 namelen = strnlen(name, XATTR_MAXNAMELEN);
360 if (name[namelen] != '\0')
91447636 361 return (ENAMETOOLONG);
2d21ac55
A
362
363 if (utf8_validatestr((const unsigned char *)name, namelen) != 0)
91447636 364 return (EINVAL);
6601e61a 365
91447636
A
366 return (0);
367}
368
369
370/*
371 * Determine whether an EA is a protected system attribute.
372 */
373int
374xattr_protected(const char *attrname)
375{
376 return(!strncmp(attrname, "com.apple.system.", 17));
377}
378
379
2d21ac55
A
380#if NAMEDSTREAMS
381/*
382 * Obtain a named stream from vnode vp.
383 */
384errno_t
385vnode_getnamedstream(vnode_t vp, vnode_t *svpp, const char *name, enum nsoperation op, int flags, vfs_context_t context)
386{
387 int error;
388
389 if (vp->v_mount->mnt_kern_flag & MNTK_NAMED_STREAMS)
390 error = VNOP_GETNAMEDSTREAM(vp, svpp, name, op, flags, context);
391 else
392 error = default_getnamedstream(vp, svpp, name, op, context);
393
394 if (error == 0) {
c910b4d9 395 uint32_t streamflags = VISNAMEDSTREAM;
2d21ac55 396 vnode_t svp = *svpp;
c910b4d9 397
b0d623f7 398 if ((vp->v_mount->mnt_kern_flag & MNTK_NAMED_STREAMS) == 0) {
c910b4d9 399 streamflags |= VISSHADOW;
b0d623f7
A
400 }
401
2d21ac55 402 /* Tag the vnode. */
c910b4d9
A
403 vnode_lock_spin(svp);
404 svp->v_flag |= streamflags;
2d21ac55 405 vnode_unlock(svp);
b0d623f7
A
406
407 /* Tag the parent so we know to flush credentials for streams on setattr */
408 vnode_lock_spin(vp);
409 vp->v_lflag |= VL_HASSTREAMS;
410 vnode_unlock(vp);
411
412 /* Make the file it's parent.
413 * Note: This parent link helps us distinguish vnodes for
414 * shadow stream files from vnodes for resource fork on file
415 * systems that support namedstream natively (both have
416 * VISNAMEDSTREAM set) by allowing access to mount structure
417 * for checking MNTK_NAMED_STREAMS bit at many places in the
418 * code.
cf7d32b8 419 */
2d21ac55
A
420 vnode_update_identity(svp, vp, NULL, 0, 0, VNODE_UPDATE_PARENT);
421 }
422
423 return (error);
424}
425
426/*
427 * Make a named stream for vnode vp.
428 */
429errno_t
430vnode_makenamedstream(vnode_t vp, vnode_t *svpp, const char *name, int flags, vfs_context_t context)
431{
432 int error;
433
434 if (vp->v_mount->mnt_kern_flag & MNTK_NAMED_STREAMS)
435 error = VNOP_MAKENAMEDSTREAM(vp, svpp, name, flags, context);
436 else
437 error = default_makenamedstream(vp, svpp, name, context);
438
439 if (error == 0) {
c910b4d9 440 uint32_t streamflags = VISNAMEDSTREAM;
2d21ac55
A
441 vnode_t svp = *svpp;
442
443 /* Tag the vnode. */
c910b4d9
A
444 if ((vp->v_mount->mnt_kern_flag & MNTK_NAMED_STREAMS) == 0) {
445 streamflags |= VISSHADOW;
446 }
b0d623f7 447
c910b4d9
A
448 /* Tag the vnode. */
449 vnode_lock_spin(svp);
450 svp->v_flag |= streamflags;
451 vnode_unlock(svp);
452
b0d623f7
A
453 /* Tag the parent so we know to flush credentials for streams on setattr */
454 vnode_lock_spin(vp);
455 vp->v_lflag |= VL_HASSTREAMS;
456 vnode_unlock(vp);
457
458 /* Make the file it's parent.
459 * Note: This parent link helps us distinguish vnodes for
460 * shadow stream files from vnodes for resource fork on file
461 * systems that support namedstream natively (both have
462 * VISNAMEDSTREAM set) by allowing access to mount structure
463 * for checking MNTK_NAMED_STREAMS bit at many places in the
464 * code.
cf7d32b8 465 */
2d21ac55
A
466 vnode_update_identity(svp, vp, NULL, 0, 0, VNODE_UPDATE_PARENT);
467 }
468 return (error);
469}
470
471/*
472 * Remove a named stream from vnode vp.
473 */
474errno_t
475vnode_removenamedstream(vnode_t vp, vnode_t svp, const char *name, int flags, vfs_context_t context)
476{
477 int error;
478
479 if (vp->v_mount->mnt_kern_flag & MNTK_NAMED_STREAMS)
480 error = VNOP_REMOVENAMEDSTREAM(vp, svp, name, flags, context);
481 else
482 error = default_removenamedstream(vp, name, context);
483
484 return (error);
485}
486
487#define NS_IOBUFSIZE (128 * 1024)
488
489/*
490 * Release a named stream shadow file.
cf7d32b8
A
491 *
492 * Note: This function is called from two places where we do not need
493 * to check if the vnode has any references held before deleting the
494 * shadow file. Once from vclean() when the vnode is being reclaimed
495 * and we do not hold any references on the vnode. Second time from
496 * default_getnamedstream() when we get an error during shadow stream
497 * file initialization so that other processes who are waiting for the
498 * shadow stream file initialization by the creator will get opportunity
499 * to create and initialize the file again.
2d21ac55
A
500 */
501errno_t
502vnode_relenamedstream(vnode_t vp, vnode_t svp, vfs_context_t context)
503{
504 vnode_t dvp;
505 struct componentname cn;
b0d623f7 506 char tmpname[80];
2d21ac55
A
507 errno_t err;
508
2d21ac55
A
509 cache_purge(svp);
510
511 vnode_lock(svp);
512 MAKE_SHADOW_NAME(vp, tmpname);
513 vnode_unlock(svp);
514
515 cn.cn_nameiop = DELETE;
516 cn.cn_flags = ISLASTCN;
517 cn.cn_context = context;
518 cn.cn_pnbuf = tmpname;
519 cn.cn_pnlen = sizeof(tmpname);
520 cn.cn_nameptr = cn.cn_pnbuf;
521 cn.cn_namelen = strlen(tmpname);
522
523 /* Obtain the vnode for the shadow files directory. */
524 err = get_shadow_dir(&dvp, context);
525 if (err != 0) {
526 return err;
527 }
b0d623f7 528
cf7d32b8 529 (void) VNOP_REMOVE(dvp, svp, &cn, 0, context);
2d21ac55
A
530 vnode_put(dvp);
531
532 return (0);
533}
534
535/*
536 * Flush a named stream shadow file.
537 */
538errno_t
539vnode_flushnamedstream(vnode_t vp, vnode_t svp, vfs_context_t context)
540{
541 struct vnode_attr va;
542 uio_t auio = NULL;
543 caddr_t bufptr = NULL;
544 size_t bufsize = 0;
545 size_t offset;
546 size_t iosize;
547 size_t datasize;
548 int error;
549
550 VATTR_INIT(&va);
551 VATTR_WANTED(&va, va_data_size);
552 if (VNOP_GETATTR(svp, &va, context) != 0 ||
553 !VATTR_IS_SUPPORTED(&va, va_data_size)) {
554 return (0);
555 }
556 datasize = va.va_data_size;
6d2010ae 557 if (datasize == 0) {
2d21ac55
A
558 (void) default_removexattr(vp, XATTR_RESOURCEFORK_NAME, 0, context);
559 return (0);
560 }
561
562 iosize = bufsize = MIN(datasize, NS_IOBUFSIZE);
563 if (kmem_alloc(kernel_map, (vm_offset_t *)&bufptr, bufsize)) {
564 return (ENOMEM);
565 }
b0d623f7 566 auio = uio_create(1, 0, UIO_SYSSPACE, UIO_READ);
2d21ac55
A
567 offset = 0;
568
569 /*
570 * Copy the shadow stream file data into the resource fork.
571 */
572 error = VNOP_OPEN(svp, 0, context);
573 if (error) {
574 printf("vnode_flushnamedstream: err %d opening file\n", error);
575 goto out;
576 }
577 while (offset < datasize) {
578 iosize = MIN(datasize - offset, iosize);
579
b0d623f7 580 uio_reset(auio, offset, UIO_SYSSPACE, UIO_READ);
2d21ac55
A
581 uio_addiov(auio, (uintptr_t)bufptr, iosize);
582 error = VNOP_READ(svp, auio, 0, context);
583 if (error) {
584 break;
585 }
586 /* Since there's no truncate xattr we must remove the resource fork. */
587 if (offset == 0) {
588 error = default_removexattr(vp, XATTR_RESOURCEFORK_NAME, 0, context);
589 if ((error != 0) && (error != ENOATTR)) {
590 break;
591 }
592 }
b0d623f7 593 uio_reset(auio, offset, UIO_SYSSPACE, UIO_WRITE);
2d21ac55
A
594 uio_addiov(auio, (uintptr_t)bufptr, iosize);
595 error = vn_setxattr(vp, XATTR_RESOURCEFORK_NAME, auio, XATTR_NOSECURITY, context);
596 if (error) {
597 break;
598 }
599 offset += iosize;
600 }
601 (void) VNOP_CLOSE(svp, 0, context);
602out:
603 if (bufptr) {
604 kmem_free(kernel_map, (vm_offset_t)bufptr, bufsize);
605 }
606 if (auio) {
607 uio_free(auio);
608 }
609 return (error);
610}
611
612
613static int
614getshadowfile(vnode_t vp, vnode_t *svpp, int makestream, size_t *rsrcsize,
615 int *creator, vfs_context_t context)
616{
617 vnode_t dvp = NULLVP;
618 vnode_t svp = NULLVP;
619 struct componentname cn;
620 struct vnode_attr va;
b0d623f7 621 char tmpname[80];
2d21ac55
A
622 size_t datasize = 0;
623 int error = 0;
6d2010ae 624 int retries = 0;
2d21ac55 625
6d2010ae 626retry_create:
2d21ac55 627 *creator = 0;
2d21ac55
A
628 /* Establish a unique file name. */
629 MAKE_SHADOW_NAME(vp, tmpname);
630 bzero(&cn, sizeof(cn));
631 cn.cn_nameiop = LOOKUP;
632 cn.cn_flags = ISLASTCN;
633 cn.cn_context = context;
634 cn.cn_pnbuf = tmpname;
635 cn.cn_pnlen = sizeof(tmpname);
636 cn.cn_nameptr = cn.cn_pnbuf;
637 cn.cn_namelen = strlen(tmpname);
638
639 /* Pick up uid, gid, mode and date from original file. */
640 VATTR_INIT(&va);
641 VATTR_WANTED(&va, va_uid);
642 VATTR_WANTED(&va, va_gid);
643 VATTR_WANTED(&va, va_mode);
644 VATTR_WANTED(&va, va_create_time);
645 VATTR_WANTED(&va, va_modify_time);
646 if (VNOP_GETATTR(vp, &va, context) != 0 ||
647 !VATTR_IS_SUPPORTED(&va, va_uid) ||
648 !VATTR_IS_SUPPORTED(&va, va_gid) ||
649 !VATTR_IS_SUPPORTED(&va, va_mode)) {
650 va.va_uid = KAUTH_UID_NONE;
651 va.va_gid = KAUTH_GID_NONE;
652 va.va_mode = S_IRUSR | S_IWUSR;
653 }
654 va.va_vaflags = VA_EXCLUSIVE;
655 VATTR_SET(&va, va_type, VREG);
656 /* We no longer change the access, but we still hide it. */
657 VATTR_SET(&va, va_flags, UF_HIDDEN);
658
659 /* Obtain the vnode for the shadow files directory. */
660 if (get_shadow_dir(&dvp, context) != 0) {
661 error = ENOTDIR;
662 goto out;
663 }
664 if (!makestream) {
665 /* See if someone else already has it open. */
666 if (VNOP_LOOKUP(dvp, &svp, &cn, context) == 0) {
667 /* Double check existence by asking for size. */
668 VATTR_INIT(&va);
669 VATTR_WANTED(&va, va_data_size);
670 if (VNOP_GETATTR(svp, &va, context) == 0 &&
671 VATTR_IS_SUPPORTED(&va, va_data_size)) {
672 goto out; /* OK to use. */
673 }
674 }
675
676 /* Otherwise make sure the resource fork data exists. */
677 error = vn_getxattr(vp, XATTR_RESOURCEFORK_NAME, NULL, &datasize,
678 XATTR_NOSECURITY, context);
679 /*
680 * To maintain binary compatibility with legacy Carbon
681 * emulated resource fork support, if the resource fork
682 * doesn't exist but the Finder Info does, then act as
683 * if an empty resource fork is present (see 4724359).
684 */
685 if ((error == ENOATTR) &&
686 (vn_getxattr(vp, XATTR_FINDERINFO_NAME, NULL, &datasize,
687 XATTR_NOSECURITY, context) == 0)) {
688 datasize = 0;
689 error = 0;
690 } else {
691 if (error) {
692 goto out;
693 }
694
695 /* If the resource fork exists, its size is expected to be non-zero. */
696 if (datasize == 0) {
697 error = ENOATTR;
698 goto out;
699 }
700 }
701 }
702 /* Create the shadow stream file. */
703 error = VNOP_CREATE(dvp, &svp, &cn, &va, context);
704 if (error == 0) {
7e4a7d39 705 vnode_recycle(svp);
2d21ac55 706 *creator = 1;
6d2010ae
A
707 }
708 else if ((error == EEXIST) && !makestream) {
2d21ac55
A
709 error = VNOP_LOOKUP(dvp, &svp, &cn, context);
710 }
6d2010ae
A
711 else if ((error == ENOENT) && !makestream) {
712 /*
713 * We could have raced with a rmdir on the shadow directory
714 * post-lookup. Retry from the beginning, 1x only, to
715 * try and see if we need to re-create the shadow directory
716 * in get_shadow_dir.
717 */
718 if (retries == 0) {
719 retries++;
720 if (dvp) {
721 vnode_put (dvp);
722 dvp = NULLVP;
723 }
724 if (svp) {
725 vnode_put (svp);
726 svp = NULLVP;
727 }
728 goto retry_create;
729 }
730 /* Otherwise, just error out normally below */
731 }
732
2d21ac55
A
733out:
734 if (dvp) {
735 vnode_put(dvp);
736 }
737 if (error) {
738 /* On errors, clean up shadow stream file. */
739 if (svp) {
740 vnode_put(svp);
741 svp = NULLVP;
742 }
743 }
744 *svpp = svp;
745 if (rsrcsize) {
746 *rsrcsize = datasize;
747 }
748 return (error);
749}
750
751
752static int
753default_getnamedstream(vnode_t vp, vnode_t *svpp, const char *name, enum nsoperation op, vfs_context_t context)
754{
755 vnode_t svp = NULLVP;
756 uio_t auio = NULL;
757 caddr_t bufptr = NULL;
758 size_t bufsize = 0;
759 size_t datasize = 0;
760 int creator;
761 int error;
762
763 /*
764 * Only the "com.apple.ResourceFork" stream is supported here.
765 */
766 if (bcmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) != 0) {
767 *svpp = NULLVP;
768 return (ENOATTR);
769 }
770retry:
771 /*
772 * Obtain a shadow file for the resource fork I/O.
773 */
774 error = getshadowfile(vp, &svp, 0, &datasize, &creator, context);
775 if (error) {
776 *svpp = NULLVP;
777 return (error);
778 }
779
780 /*
781 * The creator of the shadow file provides its file data,
b0d623f7
A
782 * all other threads should wait until its ready. In order to
783 * prevent a deadlock during error codepaths, we need to check if the
784 * vnode is being created, or if it has failed out. Regardless of success or
785 * failure, we set the VISSHADOW bit on the vnode, so we check that
786 * if the vnode's flags don't have VISNAMEDSTREAM set. If it doesn't,
787 * then we can infer the creator isn't done yet. If it's there, but
788 * VISNAMEDSTREAM is not set, then we can infer it errored out and we should
789 * try again.
2d21ac55
A
790 */
791 if (!creator) {
792 vnode_lock(svp);
793 if (svp->v_flag & VISNAMEDSTREAM) {
794 /* data is ready, go use it */
795 vnode_unlock(svp);
796 goto out;
797 } else {
b0d623f7
A
798 /* It's not ready, wait for it (sleep using v_parent as channel) */
799 if ((svp->v_flag & VISSHADOW)) {
800 /*
801 * No VISNAMEDSTREAM, but we did see VISSHADOW, indicating that the other
802 * thread is done with this vnode. Just unlock the vnode and try again
803 */
804 vnode_unlock(svp);
805 }
806 else {
807 /* Otherwise, sleep if the shadow file is not created yet */
808 msleep((caddr_t)&svp->v_parent, &svp->v_lock, PINOD | PDROP,
809 "getnamedstream", NULL);
810 }
2d21ac55
A
811 vnode_put(svp);
812 svp = NULLVP;
813 goto retry;
814 }
815 }
816
817 /*
818 * Copy the real resource fork data into shadow stream file.
819 */
820 if (op == NS_OPEN && datasize != 0) {
821 size_t offset;
822 size_t iosize;
823
824 iosize = bufsize = MIN(datasize, NS_IOBUFSIZE);
825 if (kmem_alloc(kernel_map, (vm_offset_t *)&bufptr, bufsize)) {
826 error = ENOMEM;
827 goto out;
828 }
829
b0d623f7 830 auio = uio_create(1, 0, UIO_SYSSPACE, UIO_READ);
2d21ac55
A
831 offset = 0;
832
833 error = VNOP_OPEN(svp, 0, context);
834 if (error) {
835 goto out;
836 }
837 while (offset < datasize) {
838 size_t tmpsize;
839
840 iosize = MIN(datasize - offset, iosize);
841
b0d623f7 842 uio_reset(auio, offset, UIO_SYSSPACE, UIO_READ);
2d21ac55
A
843 uio_addiov(auio, (uintptr_t)bufptr, iosize);
844 error = vn_getxattr(vp, XATTR_RESOURCEFORK_NAME, auio, &tmpsize,
845 XATTR_NOSECURITY, context);
846 if (error) {
847 break;
848 }
849
b0d623f7 850 uio_reset(auio, offset, UIO_SYSSPACE, UIO_WRITE);
2d21ac55
A
851 uio_addiov(auio, (uintptr_t)bufptr, iosize);
852 error = VNOP_WRITE(svp, auio, 0, context);
853 if (error) {
854 break;
855 }
856 offset += iosize;
857 }
858 (void) VNOP_CLOSE(svp, 0, context);
859 }
860out:
861 /* Wake up anyone waiting for svp file content */
862 if (creator) {
863 if (error == 0) {
864 vnode_lock(svp);
b0d623f7
A
865 /* VISSHADOW would be set later on anyway, so we set it now */
866 svp->v_flag |= (VISNAMEDSTREAM | VISSHADOW);
2d21ac55
A
867 wakeup((caddr_t)&svp->v_parent);
868 vnode_unlock(svp);
869 } else {
b0d623f7
A
870 /* On post create errors, get rid of the shadow file. This
871 * way if there is another process waiting for initialization
872 * of the shadowfile by the current process will wake up and
873 * retry by creating and initializing the shadow file again.
874 * Also add the VISSHADOW bit here to indicate we're done operating
875 * on this vnode.
cf7d32b8 876 */
b0d623f7
A
877 (void)vnode_relenamedstream(vp, svp, context);
878 vnode_lock (svp);
879 svp->v_flag |= VISSHADOW;
2d21ac55 880 wakeup((caddr_t)&svp->v_parent);
b0d623f7 881 vnode_unlock(svp);
2d21ac55
A
882 }
883 }
884
885 if (bufptr) {
886 kmem_free(kernel_map, (vm_offset_t)bufptr, bufsize);
887 }
888 if (auio) {
889 uio_free(auio);
890 }
891 if (error) {
892 /* On errors, clean up shadow stream file. */
893 if (svp) {
894 vnode_put(svp);
895 svp = NULLVP;
896 }
897 }
898 *svpp = svp;
899 return (error);
900}
901
902static int
903default_makenamedstream(vnode_t vp, vnode_t *svpp, const char *name, vfs_context_t context)
904{
905 int creator;
906 int error;
907
908 /*
909 * Only the "com.apple.ResourceFork" stream is supported here.
910 */
911 if (bcmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) != 0) {
912 *svpp = NULLVP;
913 return (ENOATTR);
914 }
915 error = getshadowfile(vp, svpp, 1, NULL, &creator, context);
916
917 /*
918 * Wake up any waiters over in default_getnamedstream().
919 */
920 if ((error == 0) && (*svpp != NULL) && creator) {
921 vnode_t svp = *svpp;
922
923 vnode_lock(svp);
b0d623f7
A
924 /* If we're the creator, mark it as a named stream */
925 svp->v_flag |= (VISNAMEDSTREAM | VISSHADOW);
2d21ac55
A
926 /* Wakeup any waiters on the v_parent channel */
927 wakeup((caddr_t)&svp->v_parent);
928 vnode_unlock(svp);
b0d623f7 929
2d21ac55 930 }
b0d623f7 931
2d21ac55
A
932 return (error);
933}
934
935static int
936default_removenamedstream(vnode_t vp, const char *name, vfs_context_t context)
937{
938 /*
939 * Only the "com.apple.ResourceFork" stream is supported here.
940 */
941 if (bcmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) != 0) {
942 return (ENOATTR);
943 }
944 /*
945 * XXX - what about other opened instances?
946 */
947 return default_removexattr(vp, XATTR_RESOURCEFORK_NAME, 0, context);
948}
949
950static int
951get_shadow_dir(vnode_t *sdvpp, vfs_context_t context)
952{
953 vnode_t dvp = NULLVP;
954 vnode_t sdvp = NULLVP;
955 struct componentname cn;
956 struct vnode_attr va;
b0d623f7 957 char tmpname[80];
2d21ac55
A
958 uint32_t tmp_fsid;
959 int error;
960
6d2010ae
A
961
962 bzero(tmpname, sizeof(tmpname));
963 snprintf(tmpname, sizeof(tmpname), "/var/run/.vfs_rsrc_streams_%p%x",
964 (void*)rootvnode, shadow_sequence);
965 /*
966 * Look up the shadow directory to ensure that it still exists.
967 * By looking it up, we get an iocounted dvp to use, and avoid some coherency issues
968 * in caching it when multiple threads may be trying to manipulate the pointers.
969 */
970 error = vnode_lookup(tmpname, 0, &sdvp, context);
971 if (error == 0) {
972 /*
973 * If we get here, then we have successfully looked up the shadow dir,
974 * and it has an iocount from the lookup. Return the vp in the output argument.
975 */
976 *sdvpp = sdvp;
977 return (0);
2d21ac55 978 }
6d2010ae
A
979 /* In the failure case, no iocount is acquired */
980 sdvp = NULLVP;
981 bzero (tmpname, sizeof(tmpname));
2d21ac55 982
0b4c1975
A
983 /* Obtain the vnode for "/var/run" directory. */
984 if (vnode_lookup("/var/run", 0, &dvp, context) != 0) {
2d21ac55
A
985 error = ENOTSUP;
986 goto out;
987 }
988
989 /* Create the shadow stream directory. */
b0d623f7
A
990 snprintf(tmpname, sizeof(tmpname), ".vfs_rsrc_streams_%p%x",
991 (void*)rootvnode, shadow_sequence);
2d21ac55
A
992 bzero(&cn, sizeof(cn));
993 cn.cn_nameiop = LOOKUP;
994 cn.cn_flags = ISLASTCN;
995 cn.cn_context = context;
996 cn.cn_pnbuf = tmpname;
997 cn.cn_pnlen = sizeof(tmpname);
998 cn.cn_nameptr = cn.cn_pnbuf;
999 cn.cn_namelen = strlen(tmpname);
1000
1001 /*
1002 * owned by root, only readable by root, hidden
1003 */
1004 VATTR_INIT(&va);
1005 VATTR_SET(&va, va_uid, 0);
1006 VATTR_SET(&va, va_gid, 0);
1007 VATTR_SET(&va, va_mode, S_IRUSR | S_IXUSR);
1008 VATTR_SET(&va, va_type, VDIR);
1009 VATTR_SET(&va, va_flags, UF_HIDDEN);
1010 va.va_vaflags = VA_EXCLUSIVE;
1011
1012 error = VNOP_MKDIR(dvp, &sdvp, &cn, &va, context);
1013
1014 /*
1015 * There can be only one winner for an exclusive create.
1016 */
6d2010ae 1017 if (error == EEXIST) {
2d21ac55
A
1018 /* loser has to look up directory */
1019 error = VNOP_LOOKUP(dvp, &sdvp, &cn, context);
1020 if (error == 0) {
1021 /* Make sure its in fact a directory */
1022 if (sdvp->v_type != VDIR) {
1023 goto baddir;
1024 }
6d2010ae 1025 /* Obtain the fsid for /tmp directory */
2d21ac55
A
1026 VATTR_INIT(&va);
1027 VATTR_WANTED(&va, va_fsid);
1028 if (VNOP_GETATTR(dvp, &va, context) != 0 ||
1029 !VATTR_IS_SUPPORTED(&va, va_fsid)) {
1030 goto baddir;
1031 }
1032 tmp_fsid = va.va_fsid;
1033
1034 VATTR_INIT(&va);
1035 VATTR_WANTED(&va, va_uid);
1036 VATTR_WANTED(&va, va_gid);
1037 VATTR_WANTED(&va, va_mode);
1038 VATTR_WANTED(&va, va_fsid);
1039 VATTR_WANTED(&va, va_dirlinkcount);
1040 VATTR_WANTED(&va, va_acl);
1041 /* Provide defaults for attrs that may not be supported */
1042 va.va_dirlinkcount = 1;
1043 va.va_acl = (kauth_acl_t) KAUTH_FILESEC_NONE;
1044
1045 if (VNOP_GETATTR(sdvp, &va, context) != 0 ||
1046 !VATTR_IS_SUPPORTED(&va, va_uid) ||
1047 !VATTR_IS_SUPPORTED(&va, va_gid) ||
1048 !VATTR_IS_SUPPORTED(&va, va_mode) ||
1049 !VATTR_IS_SUPPORTED(&va, va_fsid)) {
1050 goto baddir;
1051 }
1052 /*
1053 * Make sure its what we want:
1054 * - owned by root
1055 * - not writable by anyone
1056 * - on same file system as /tmp
1057 * - not a hard-linked directory
1058 * - no ACLs (they might grant write access)
1059 */
1060 if ((va.va_uid != 0) || (va.va_gid != 0) ||
1061 (va.va_mode & (S_IWUSR | S_IRWXG | S_IRWXO)) ||
1062 (va.va_fsid != tmp_fsid) ||
1063 (va.va_dirlinkcount != 1) ||
1064 (va.va_acl != (kauth_acl_t) KAUTH_FILESEC_NONE)) {
1065 goto baddir;
1066 }
1067 }
1068 }
1069out:
1070 if (dvp) {
1071 vnode_put(dvp);
1072 }
1073 if (error) {
1074 /* On errors, clean up shadow stream directory. */
1075 if (sdvp) {
1076 vnode_put(sdvp);
1077 sdvp = NULLVP;
1078 }
1079 }
1080 *sdvpp = sdvp;
1081 return (error);
1082
1083baddir:
1084 /* This is not the dir we're looking for, move along */
1085 ++shadow_sequence; /* try something else next time */
1086 error = ENOTDIR;
1087 goto out;
1088}
1089#endif
1090
1091
1092
91447636
A
1093/*
1094 * Default Implementation (Non-native EA)
1095 */
1096
1097
1098/*
1099 Typical "._" AppleDouble Header File layout:
1100 ------------------------------------------------------------
1101 MAGIC 0x00051607
1102 VERSION 0x00020000
1103 FILLER 0
1104 COUNT 2
1105 .-- AD ENTRY[0] Finder Info Entry (must be first)
1106 .--+-- AD ENTRY[1] Resource Fork Entry (must be last)
1107 | '-> FINDER INFO
1108 | ///////////// Fixed Size Data (32 bytes)
1109 | EXT ATTR HDR
1110 | /////////////
1111 | ATTR ENTRY[0] --.
1112 | ATTR ENTRY[1] --+--.
1113 | ATTR ENTRY[2] --+--+--.
1114 | ... | | |
1115 | ATTR ENTRY[N] --+--+--+--.
1116 | ATTR DATA 0 <-' | | |
1117 | //////////// | | |
1118 | ATTR DATA 1 <----' | |
1119 | ///////////// | |
1120 | ATTR DATA 2 <-------' |
1121 | ///////////// |
1122 | ... |
1123 | ATTR DATA N <----------'
1124 | /////////////
1125 | Attribute Free Space
1126 |
1127 '----> RESOURCE FORK
1128 ///////////// Variable Sized Data
1129 /////////////
1130 /////////////
1131 /////////////
1132 /////////////
1133 /////////////
1134 ...
1135 /////////////
1136
1137 ------------------------------------------------------------
1138
1139 NOTE: The EXT ATTR HDR, ATTR ENTRY's and ATTR DATA's are
1140 stored as part of the Finder Info. The length in the Finder
1141 Info AppleDouble entry includes the length of the extended
1142 attribute header, attribute entries, and attribute data.
1143*/
1144
1145
1146/*
1147 * On Disk Data Structures
1148 *
1149 * Note: Motorola 68K alignment and big-endian.
1150 *
1151 * See RFC 1740 for additional information about the AppleDouble file format.
1152 *
1153 */
1154
1155#define ADH_MAGIC 0x00051607
1156#define ADH_VERSION 0x00020000
1157#define ADH_MACOSX "Mac OS X "
1158
1159/*
1160 * AppleDouble Entry ID's
1161 */
1162#define AD_DATA 1 /* Data fork */
1163#define AD_RESOURCE 2 /* Resource fork */
1164