1/* 2 * Copyright (c) 2004 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 <errno.h> 26#include <fcntl.h> 27#include <unistd.h> 28#include <uuid/uuid.h> 29 30#if 1 /* for turdfile code only */ 31#include <string.h> 32#include <sys/stat.h> 33#include <stdio.h> 34#include <stdlib.h> 35#endif 36 37static int chmodx_syscall(void *obj, uid_t fsowner, gid_t fsgrp, int mode, kauth_filesec_t fsacl); 38static int fchmodx_syscall(void *obj, uid_t fsowner, gid_t fsgrp, int mode, kauth_filesec_t fsacl); 39 40static int chmodx1(void *obj, 41 int (* chmod_syscall)(void *obj, uid_t fsowner, gid_t fsgrp, int mode, 42 kauth_filesec_t fsacl), 43 filesec_t fsec); 44 45/* 46 * Chmod interfaces. 47 */ 48int 49chmodx_np(const char *path, filesec_t fsec) 50{ 51 return(chmodx1((void *)&path, chmodx_syscall, fsec)); 52} 53 54int 55fchmodx_np(int fd, filesec_t fsec) 56{ 57 return(chmodx1((void *)&fd, fchmodx_syscall, fsec)); 58} 59 60/* 61 * Chmod syscalls. 62 */ 63extern int __chmod_extended(char *, uid_t, gid_t, int, kauth_filesec_t); 64extern int __fchmod_extended(int, uid_t, gid_t, int, kauth_filesec_t); 65 66static int 67chmodx_syscall(void *obj, uid_t fsowner, gid_t fsgrp, int mode, kauth_filesec_t fsacl) 68{ 69 char *path = *(char **)obj; 70 71 return(__chmod_extended(path, fsowner, fsgrp, mode, fsacl)); 72} 73 74static int 75fchmodx_syscall(void *obj, uid_t fsowner, gid_t fsgrp, int mode, kauth_filesec_t fsacl) 76{ 77 int fd = *(int *)obj; 78 return(__fchmod_extended(fd, fsowner, fsgrp, mode, fsacl)); 79} 80 81/* 82 * Chmod internals. 83 */ 84 85static int 86chmodx1(void *obj, 87 int (chmod_syscall)(void *obj, uid_t fsowner, gid_t fsgrp, int mode, kauth_filesec_t fsacl), 88 filesec_t fsec) 89{ 90 uid_t fsowner = KAUTH_UID_NONE; 91 gid_t fsgrp = KAUTH_GID_NONE; 92 mode_t fsec_mode; 93 int fsmode = -1; 94 size_t size = 0; 95 int fsacl_used = 0; 96 int delete_acl = 0; 97 kauth_filesec_t fsacl = KAUTH_FILESEC_NONE; 98 struct kauth_filesec static_filesec; 99 100 if (fsec == NULL) { 101 errno = EINVAL; 102 return(-1); 103 } 104 105 /* regular properties */ 106 if ((filesec_get_property(fsec, FILESEC_OWNER, &fsowner) != 0) && (errno != ENOENT)) 107 return(-1); 108 if ((filesec_get_property(fsec, FILESEC_GROUP, &fsgrp) != 0) && (errno != ENOENT)) 109 return(-1); 110 if ((filesec_get_property(fsec, FILESEC_MODE, &fsec_mode)) != 0) { 111 if (errno != ENOENT) 112 return(-1); 113 } else { 114 /* cast up */ 115 fsmode = fsec_mode; 116 } 117 118 /* 119 * We can set any or all of the ACL and UUIDs, but the two are transported in one 120 * structure. If we have an ACL, we'll use its allocated structure, otherwise we 121 * need our own. 122 */ 123 if (((filesec_get_property(fsec, FILESEC_ACL_RAW, &fsacl) != 0) || 124 (filesec_get_property(fsec, FILESEC_ACL_ALLOCSIZE, &size) != 0)) && 125 (errno != ENOENT)) 126 return(-1); 127 /* caller wants to delete ACL, must remember this */ 128 if (fsacl == _FILESEC_REMOVE_ACL) { 129 delete_acl = 1; 130 fsacl = 0; 131 } 132 133 /* no ACL, use local filesec */ 134 if (fsacl == KAUTH_FILESEC_NONE) { 135 bzero(&static_filesec, sizeof(static_filesec)); 136 fsacl = &static_filesec; 137 fsacl->fsec_magic = KAUTH_FILESEC_MAGIC; 138 fsacl->fsec_entrycount = KAUTH_FILESEC_NOACL; 139 } else { 140 fsacl_used = 1; 141 } 142 143 /* grab the owner and group UUID if present */ 144 if (filesec_get_property(fsec, FILESEC_UUID, &fsacl->fsec_owner) != 0) { 145 if (errno != ENOENT) 146 return(-1); 147 bzero(&fsacl->fsec_owner, sizeof(fsacl->fsec_owner)); 148 } else { 149 fsacl_used = 1; 150 } 151 if (filesec_get_property(fsec, FILESEC_GRPUUID, &fsacl->fsec_group) != 0) { 152 if (errno != ENOENT) 153 return(-1); 154 bzero(&fsacl->fsec_group, sizeof(fsacl->fsec_group)); 155 } else { 156 fsacl_used = 1; 157 } 158 159 /* after all this, if we didn't find anything that needs it, don't pass it in */ 160 if (!fsacl_used) { 161 /* 162 * If the caller was trying to remove the ACL, and there are no UUIDs, 163 * we can tell the kernel to completely nuke the whole datastructure. 164 */ 165 if (delete_acl) { 166 fsacl = _FILESEC_REMOVE_ACL; 167 } else { 168 fsacl = KAUTH_FILESEC_NONE; 169 } 170 } 171 172 return(chmod_syscall(obj, fsowner, fsgrp, fsmode, fsacl)); 173} 174