1/* 2 Unix SMB/Netbios implementation. 3 VFS module to get and set posix acls 4 Copyright (C) Volker Lendecke 2006 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program; if not, write to the Free Software 18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19*/ 20 21#include "includes.h" 22 23 24/* prototypes for static functions first - for clarity */ 25 26static BOOL smb_ace_to_internal(acl_entry_t posix_ace, 27 struct smb_acl_entry *ace); 28static struct smb_acl_t *smb_acl_to_internal(acl_t acl); 29static int smb_acl_set_mode(acl_entry_t entry, SMB_ACL_PERM_T perm); 30static acl_t smb_acl_to_posix(const struct smb_acl_t *acl); 31 32 33/* public functions - the api */ 34 35SMB_ACL_T posixacl_sys_acl_get_file(vfs_handle_struct *handle, 36 const char *path_p, 37 SMB_ACL_TYPE_T type) 38{ 39 struct smb_acl_t *result; 40 acl_type_t acl_type; 41 acl_t acl; 42 43 switch(type) { 44 case SMB_ACL_TYPE_ACCESS: 45 acl_type = ACL_TYPE_ACCESS; 46 break; 47 case SMB_ACL_TYPE_DEFAULT: 48 acl_type = ACL_TYPE_DEFAULT; 49 break; 50 default: 51 errno = EINVAL; 52 return NULL; 53 } 54 55 acl = acl_get_file(path_p, acl_type); 56 57 if (acl == NULL) { 58 return NULL; 59 } 60 61 result = smb_acl_to_internal(acl); 62 acl_free(acl); 63 return result; 64} 65 66SMB_ACL_T posixacl_sys_acl_get_fd(vfs_handle_struct *handle, 67 files_struct *fsp, 68 int fd) 69{ 70 struct smb_acl_t *result; 71 acl_t acl = acl_get_fd(fd); 72 73 if (acl == NULL) { 74 return NULL; 75 } 76 77 result = smb_acl_to_internal(acl); 78 acl_free(acl); 79 return result; 80} 81 82int posixacl_sys_acl_set_file(vfs_handle_struct *handle, 83 const char *name, 84 SMB_ACL_TYPE_T type, 85 SMB_ACL_T theacl) 86{ 87 int res; 88 acl_type_t acl_type; 89 acl_t acl; 90 91 DEBUG(10, ("Calling acl_set_file: %s, %d\n", name, type)); 92 93 switch(type) { 94 case SMB_ACL_TYPE_ACCESS: 95 acl_type = ACL_TYPE_ACCESS; 96 break; 97 case SMB_ACL_TYPE_DEFAULT: 98 acl_type = ACL_TYPE_DEFAULT; 99 break; 100 default: 101 errno = EINVAL; 102 return -1; 103 } 104 105 if ((acl = smb_acl_to_posix(theacl)) == NULL) { 106 return -1; 107 } 108 res = acl_set_file(name, acl_type, acl); 109 if (res != 0) { 110 DEBUG(10, ("acl_set_file failed: %s\n", strerror(errno))); 111 } 112 acl_free(acl); 113 return res; 114} 115 116int posixacl_sys_acl_set_fd(vfs_handle_struct *handle, 117 files_struct *fsp, 118 int fd, SMB_ACL_T theacl) 119{ 120 int res; 121 acl_t acl = smb_acl_to_posix(theacl); 122 if (acl == NULL) { 123 return -1; 124 } 125 res = acl_set_fd(fd, acl); 126 acl_free(acl); 127 return res; 128} 129 130int posixacl_sys_acl_delete_def_file(vfs_handle_struct *handle, 131 const char *path) 132{ 133 return acl_delete_def_file(path); 134} 135 136 137/* private functions */ 138 139static BOOL smb_ace_to_internal(acl_entry_t posix_ace, 140 struct smb_acl_entry *ace) 141{ 142 acl_tag_t tag; 143 acl_permset_t permset; 144 145 if (acl_get_tag_type(posix_ace, &tag) != 0) { 146 DEBUG(0, ("smb_acl_get_tag_type failed\n")); 147 return False; 148 } 149 150 switch(tag) { 151 case ACL_USER: 152 ace->a_type = SMB_ACL_USER; 153 break; 154 case ACL_USER_OBJ: 155 ace->a_type = SMB_ACL_USER_OBJ; 156 break; 157 case ACL_GROUP: 158 ace->a_type = SMB_ACL_GROUP; 159 break; 160 case ACL_GROUP_OBJ: 161 ace->a_type = SMB_ACL_GROUP_OBJ; 162 break; 163 case ACL_OTHER: 164 ace->a_type = SMB_ACL_OTHER; 165 break; 166 case ACL_MASK: 167 ace->a_type = SMB_ACL_MASK; 168 break; 169 default: 170 DEBUG(0, ("unknown tag type %d\n", (unsigned int)tag)); 171 return False; 172 } 173 switch(ace->a_type) { 174 case SMB_ACL_USER: { 175 uid_t *puid = (uid_t *)acl_get_qualifier(posix_ace); 176 if (puid == NULL) { 177 DEBUG(0, ("smb_acl_get_qualifier failed\n")); 178 return False; 179 } 180 ace->uid = *puid; 181 acl_free(puid); 182 break; 183 } 184 185 case SMB_ACL_GROUP: { 186 gid_t *pgid = (uid_t *)acl_get_qualifier(posix_ace); 187 if (pgid == NULL) { 188 DEBUG(0, ("smb_acl_get_qualifier failed\n")); 189 return False; 190 } 191 ace->gid = *pgid; 192 acl_free(pgid); 193 break; 194 } 195 default: 196 break; 197 } 198 if (acl_get_permset(posix_ace, &permset) != 0) { 199 DEBUG(0, ("smb_acl_get_mode failed\n")); 200 return False; 201 } 202 ace->a_perm = 0; 203#ifdef HAVE_ACL_GET_PERM_NP 204 ace->a_perm |= (acl_get_perm_np(permset, ACL_READ) ? SMB_ACL_READ : 0); 205 ace->a_perm |= (acl_get_perm_np(permset, ACL_WRITE) ? SMB_ACL_WRITE : 0); 206 ace->a_perm |= (acl_get_perm_np(permset, ACL_EXECUTE) ? SMB_ACL_EXECUTE : 0); 207#else 208 ace->a_perm |= (acl_get_perm(permset, ACL_READ) ? SMB_ACL_READ : 0); 209 ace->a_perm |= (acl_get_perm(permset, ACL_WRITE) ? SMB_ACL_WRITE : 0); 210 ace->a_perm |= (acl_get_perm(permset, ACL_EXECUTE) ? SMB_ACL_EXECUTE : 0); 211#endif 212 return True; 213} 214 215static struct smb_acl_t *smb_acl_to_internal(acl_t acl) 216{ 217 struct smb_acl_t *result = SMB_MALLOC_P(struct smb_acl_t); 218 int entry_id = ACL_FIRST_ENTRY; 219 acl_entry_t e; 220 if (result == NULL) { 221 return NULL; 222 } 223 ZERO_STRUCTP(result); 224 while (acl_get_entry(acl, entry_id, &e) == 1) { 225 226 entry_id = ACL_NEXT_ENTRY; 227 228 result = (struct smb_acl_t *)SMB_REALLOC( 229 result, sizeof(struct smb_acl_t) + 230 (sizeof(struct smb_acl_entry) * (result->count+1))); 231 if (result == NULL) { 232 DEBUG(0, ("SMB_REALLOC failed\n")); 233 errno = ENOMEM; 234 return NULL; 235 } 236 237 if (!smb_ace_to_internal(e, &result->acl[result->count])) { 238 SAFE_FREE(result); 239 return NULL; 240 } 241 242 result->count += 1; 243 } 244 return result; 245} 246 247static int smb_acl_set_mode(acl_entry_t entry, SMB_ACL_PERM_T perm) 248{ 249 int ret; 250 acl_permset_t permset; 251 252 if ((ret = acl_get_permset(entry, &permset)) != 0) { 253 return ret; 254 } 255 if ((ret = acl_clear_perms(permset)) != 0) { 256 return ret; 257 } 258 if ((perm & SMB_ACL_READ) && 259 ((ret = acl_add_perm(permset, ACL_READ)) != 0)) { 260 return ret; 261 } 262 if ((perm & SMB_ACL_WRITE) && 263 ((ret = acl_add_perm(permset, ACL_WRITE)) != 0)) { 264 return ret; 265 } 266 if ((perm & SMB_ACL_EXECUTE) && 267 ((ret = acl_add_perm(permset, ACL_EXECUTE)) != 0)) { 268 return ret; 269 } 270 return acl_set_permset(entry, permset); 271} 272 273static acl_t smb_acl_to_posix(const struct smb_acl_t *acl) 274{ 275 acl_t result; 276 int i; 277 278 result = acl_init(acl->count); 279 if (result == NULL) { 280 DEBUG(10, ("acl_init failed\n")); 281 return NULL; 282 } 283 284 for (i=0; i<acl->count; i++) { 285 const struct smb_acl_entry *entry = &acl->acl[i]; 286 acl_entry_t e; 287 acl_tag_t tag; 288 289 if (acl_create_entry(&result, &e) != 0) { 290 DEBUG(1, ("acl_create_entry failed: %s\n", 291 strerror(errno))); 292 goto fail; 293 } 294 295 switch (entry->a_type) { 296 case SMB_ACL_USER: 297 tag = ACL_USER; 298 break; 299 case SMB_ACL_USER_OBJ: 300 tag = ACL_USER_OBJ; 301 break; 302 case SMB_ACL_GROUP: 303 tag = ACL_GROUP; 304 break; 305 case SMB_ACL_GROUP_OBJ: 306 tag = ACL_GROUP_OBJ; 307 break; 308 case SMB_ACL_OTHER: 309 tag = ACL_OTHER; 310 break; 311 case SMB_ACL_MASK: 312 tag = ACL_MASK; 313 break; 314 default: 315 DEBUG(1, ("Unknown tag value %d\n", entry->a_type)); 316 goto fail; 317 } 318 319 if (acl_set_tag_type(e, tag) != 0) { 320 DEBUG(10, ("acl_set_tag_type(%d) failed: %s\n", 321 tag, strerror(errno))); 322 goto fail; 323 } 324 325 switch (entry->a_type) { 326 case SMB_ACL_USER: 327 if (acl_set_qualifier(e, &entry->uid) != 0) { 328 DEBUG(1, ("acl_set_qualifiier failed: %s\n", 329 strerror(errno))); 330 goto fail; 331 } 332 break; 333 case SMB_ACL_GROUP: 334 if (acl_set_qualifier(e, &entry->gid) != 0) { 335 DEBUG(1, ("acl_set_qualifiier failed: %s\n", 336 strerror(errno))); 337 goto fail; 338 } 339 break; 340 default: /* Shut up, compiler! :-) */ 341 break; 342 } 343 344 if (smb_acl_set_mode(e, entry->a_perm) != 0) { 345 goto fail; 346 } 347 } 348 349 if (acl_valid(result) != 0) { 350 DEBUG(0, ("smb_acl_to_posix: ACL is invalid for set (%s)\n", 351 strerror(errno))); 352 goto fail; 353 } 354 355 return result; 356 357 fail: 358 if (result != NULL) { 359 acl_free(result); 360 } 361 return NULL; 362} 363 364/* VFS operations structure */ 365 366static vfs_op_tuple posixacl_op_tuples[] = { 367 /* Disk operations */ 368 {SMB_VFS_OP(posixacl_sys_acl_get_file), 369 SMB_VFS_OP_SYS_ACL_GET_FILE, 370 SMB_VFS_LAYER_TRANSPARENT}, 371 372 {SMB_VFS_OP(posixacl_sys_acl_get_fd), 373 SMB_VFS_OP_SYS_ACL_GET_FD, 374 SMB_VFS_LAYER_TRANSPARENT}, 375 376 {SMB_VFS_OP(posixacl_sys_acl_set_file), 377 SMB_VFS_OP_SYS_ACL_SET_FILE, 378 SMB_VFS_LAYER_TRANSPARENT}, 379 380 {SMB_VFS_OP(posixacl_sys_acl_set_fd), 381 SMB_VFS_OP_SYS_ACL_SET_FD, 382 SMB_VFS_LAYER_TRANSPARENT}, 383 384 {SMB_VFS_OP(posixacl_sys_acl_delete_def_file), 385 SMB_VFS_OP_SYS_ACL_DELETE_DEF_FILE, 386 SMB_VFS_LAYER_TRANSPARENT}, 387 388 {SMB_VFS_OP(NULL), 389 SMB_VFS_OP_NOOP, 390 SMB_VFS_LAYER_NOOP} 391}; 392 393NTSTATUS vfs_posixacl_init(void); 394NTSTATUS vfs_posixacl_init(void) 395{ 396 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "posixacl", 397 posixacl_op_tuples); 398} 399