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