1/* 2 * Copyright (c) 2004, 2006 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 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. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23#include <sys/types.h> 24#include <sys/acl.h> 25#include <sys/stat.h> 26#include <errno.h> 27#include <stdlib.h> 28#include <unistd.h> 29#include <fcntl.h> 30 31#include <string.h> 32#include <stdio.h> 33 34#define ACL_MIN_SIZE_HEURISTIC (KAUTH_FILESEC_SIZE(16)) 35 36static int statx_syscall(void *obj, void *sbptr, void *fsacl, size_t *fsacl_size); 37static int fstatx_syscall(void *obj, void *sbptr, void *fsacl, size_t *fsacl_size); 38static int lstatx_syscall(void *obj, void *sbptr, void *fsacl, size_t *fsacl_size); 39 40static int statx1(void *obj, 41 int (* stat_syscall)(void *obj, void *sbptr, void *fsacl, size_t *fsacl_size), 42 void *sbptr, filesec_t fsec); 43 44/* 45 * Stat interfaces. 46 */ 47int 48statx_np(const char *path, struct stat *sb, filesec_t fsec) 49{ 50 if (fsec == NULL) 51 return(stat(path, sb)); 52 return(statx1((void *)&path, statx_syscall, (void *)sb, fsec)); 53} 54 55int 56fstatx_np(int fd, struct stat *sb, filesec_t fsec) 57{ 58 if (fsec == NULL) 59 return(fstat(fd, sb)); 60 return(statx1((void *)&fd, fstatx_syscall, (void *)sb, fsec)); 61} 62 63int 64lstatx_np(const char *path, struct stat *sb, filesec_t fsec) 65{ 66 if (fsec == NULL) 67 return(lstat(path, sb)); 68 return(statx1((void *)&path, lstatx_syscall, (void *)sb, fsec)); 69} 70 71 72#if __DARWIN_64_BIT_INO_T && !__DARWIN_ONLY_64_BIT_INO_T 73int 74statx64_np(const char *path, struct stat64 *sb, filesec_t fsec) 75{ 76 return(statx_np(path, (struct stat *)sb, fsec)); 77} 78 79int 80fstatx64_np(int fd, struct stat64 *sb, filesec_t fsec) 81{ 82 return(fstatx_np(fd, (struct stat *)sb, fsec)); 83} 84 85int 86lstatx64_np(const char *path, struct stat64 *sb, filesec_t fsec) 87{ 88 return(lstatx_np(path, (struct stat *)sb, fsec)); 89} 90#endif /* __DARWIN_64_BIT_INO_T && !__DARWIN_ONLY_64_BIT_INO_T */ 91 92/* 93 * Stat syscalls 94 */ 95#if __DARWIN_64_BIT_INO_T 96extern int __fstat64_extended(int, struct stat *, void *, size_t *); 97extern int __lstat64_extended(const char *, struct stat *, void *, size_t *); 98extern int __stat64_extended(const char *, struct stat *, void *, size_t *); 99#else /* !__DARWIN_64_BIT_INO_T */ 100extern int __fstat_extended(int, struct stat *, void *, size_t *); 101extern int __lstat_extended(const char *, struct stat *, void *, size_t *); 102extern int __stat_extended(const char *, struct stat *, void *, size_t *); 103#endif /* __DARWIN_64_BIT_INO_T */ 104 105static int 106statx_syscall(void *obj, void *sb, void *fsacl, size_t *fsacl_size) 107{ 108 const char *path = *(const char **)obj; 109#if __DARWIN_64_BIT_INO_T 110 return(__stat64_extended(path, (struct stat *)sb, fsacl, fsacl_size)); 111#else /* !__DARWIN_64_BIT_INO_T */ 112 return(__stat_extended(path, (struct stat *)sb, fsacl, fsacl_size)); 113#endif /* __DARWIN_64_BIT_INO_T */ 114} 115 116static int 117fstatx_syscall(void *obj, void *sb, void *fsacl, size_t *fsacl_size) 118{ 119 int fd = *(int *)obj; 120#if __DARWIN_64_BIT_INO_T 121 return(__fstat64_extended(fd, (struct stat *)sb, fsacl, fsacl_size)); 122#else /* !__DARWIN_64_BIT_INO_T */ 123 return(__fstat_extended(fd, (struct stat *)sb, fsacl, fsacl_size)); 124#endif /* __DARWIN_64_BIT_INO_T */ 125} 126 127static int 128lstatx_syscall(void *obj, void *sb, void *fsacl, size_t *fsacl_size) 129{ 130 const char *path = *(const char **)obj; 131#if __DARWIN_64_BIT_INO_T 132 return(__lstat64_extended(path, (struct stat *)sb, fsacl, fsacl_size)); 133#else /* !__DARWIN_64_BIT_INO_T */ 134 return(__lstat_extended(path, (struct stat *)sb, fsacl, fsacl_size)); 135#endif /* __DARWIN_64_BIT_INO_T */ 136} 137 138/* 139 * Stat internals 140 */ 141static int 142statx1(void *obj, 143 int (* stat_syscall)(void *obj, void *sbptr, void *fsacl, size_t *fsacl_size), 144 void *sbptr, filesec_t fsec) 145{ 146 kauth_filesec_t fsacl, ofsacl; 147 size_t fsacl_size, buffer_size; 148 int error; 149 struct stat * sb = (struct stat *)0; 150 151 fsacl = NULL; 152 error = 0; 153 154 sb = (struct stat *)sbptr; 155 156 /* 157 * Allocate an initial buffer. 158 */ 159 if ((fsacl = malloc(ACL_MIN_SIZE_HEURISTIC)) == NULL) { 160 error = ENOMEM; 161 goto out; 162 } 163 buffer_size = ACL_MIN_SIZE_HEURISTIC; 164 165 /* 166 * Loop until we have the ACL. 167 */ 168 for (;;) { 169 fsacl_size = buffer_size; 170 171 if ((error = stat_syscall(obj, sbptr, fsacl, &fsacl_size)) != 0) 172 goto out; 173 174 /* 175 * No error, did we get the ACL? 176 */ 177 if (fsacl_size <= buffer_size) 178 break; 179 180 /* no, use supplied buffer size plus some padding */ 181 ofsacl = fsacl; 182 fsacl = realloc(fsacl, fsacl_size + sizeof(struct kauth_ace) * 2); 183 if (fsacl == NULL) { 184 fsacl = ofsacl; 185 errno = ENOMEM; 186 goto out; 187 } 188 buffer_size = fsacl_size; 189 } 190 191 /* populate filesec with values from stat */ 192 filesec_set_property(fsec, FILESEC_OWNER, &(sb->st_uid)); 193 filesec_set_property(fsec, FILESEC_GROUP, &(sb->st_gid)); 194 filesec_set_property(fsec, FILESEC_MODE, &(sb->st_mode)); 195 196 /* if we got a kauth_filesec, take values from there too */ 197 if (fsacl_size >= sizeof(struct kauth_filesec)) { 198 filesec_set_property(fsec, FILESEC_UUID, &fsacl->fsec_owner); 199 filesec_set_property(fsec, FILESEC_GRPUUID, &fsacl->fsec_group); 200 201 /* check to see whether there's actually an ACL here */ 202 if (fsacl->fsec_acl.acl_entrycount != KAUTH_FILESEC_NOACL) { 203 filesec_set_property(fsec, FILESEC_ACL_ALLOCSIZE, &fsacl_size); 204 filesec_set_property(fsec, FILESEC_ACL_RAW, &fsacl); 205 fsacl = NULL; /* avoid freeing it below */ 206 } else { 207 filesec_set_property(fsec, FILESEC_ACL_ALLOCSIZE, NULL); 208 filesec_set_property(fsec, FILESEC_ACL_RAW, NULL); 209 } 210 } else { 211 filesec_set_property(fsec, FILESEC_UUID, NULL); 212 filesec_set_property(fsec, FILESEC_GRPUUID, NULL); 213 filesec_set_property(fsec, FILESEC_ACL_ALLOCSIZE, NULL); 214 filesec_set_property(fsec, FILESEC_ACL_RAW, NULL); 215 } 216out: 217 if (fsacl != NULL) 218 free(fsacl); 219 return(error); 220} 221