174465Srwatson/*- 2108450Srwatson * Copyright (c) 1999, 2001, 2002 Robert N M Watson 374465Srwatson * All rights reserved. 474465Srwatson * 586458Srwatson * This software was developed by Robert Watson for the TrustedBSD Project. 686458Srwatson * 774465Srwatson * Redistribution and use in source and binary forms, with or without 874465Srwatson * modification, are permitted provided that the following conditions 974465Srwatson * are met: 1074465Srwatson * 1. Redistributions of source code must retain the above copyright 1174465Srwatson * notice, this list of conditions and the following disclaimer. 1274465Srwatson * 2. Redistributions in binary form must reproduce the above copyright 1374465Srwatson * notice, this list of conditions and the following disclaimer in the 1474465Srwatson * documentation and/or other materials provided with the distribution. 1574465Srwatson * 1674465Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1774465Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1874465Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1974465Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2074465Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2174465Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2274465Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2374465Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2474465Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2574465Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2674465Srwatson * SUCH DAMAGE. 2774465Srwatson */ 2874465Srwatson/* 2974465Srwatson * getfacl -- POSIX.1e utility to extract ACLs from files and directories 3074465Srwatson * and send the results to stdout 3174465Srwatson */ 3274465Srwatson 3399109Sobrien 3499109Sobrien#include <sys/cdefs.h> 3599109Sobrien__FBSDID("$FreeBSD$"); 3699109Sobrien 3774465Srwatson#include <sys/types.h> 3874465Srwatson#include <sys/param.h> 3974465Srwatson#include <sys/acl.h> 4074465Srwatson#include <sys/stat.h> 4199109Sobrien 4274465Srwatson#include <err.h> 4374465Srwatson#include <errno.h> 44172237Skevlo#include <grp.h> 45172237Skevlo#include <pwd.h> 4674465Srwatson#include <stdio.h> 4775491Sjedgar#include <stdlib.h> 4876875Skris#include <string.h> 4974465Srwatson#include <unistd.h> 5074465Srwatson 51241720Sedstatic int more_than_one = 0; 5274465Srwatson 5374465Srwatsonstatic void 5474465Srwatsonusage(void) 5574465Srwatson{ 5674465Srwatson 57196827Strasz fprintf(stderr, "getfacl [-dhnqv] [file ...]\n"); 5874465Srwatson} 5974465Srwatson 60172237Skevlostatic char * 61172237Skevlogetuname(uid_t uid) 62172237Skevlo{ 63172237Skevlo struct passwd *pw; 64172237Skevlo static char uids[10]; 65172237Skevlo 66172237Skevlo if ((pw = getpwuid(uid)) == NULL) { 67172237Skevlo (void)snprintf(uids, sizeof(uids), "%u", uid); 68172237Skevlo return (uids); 69172237Skevlo } else 70172237Skevlo return (pw->pw_name); 71172237Skevlo} 72172237Skevlo 73172237Skevlostatic char * 74172237Skevlogetgname(gid_t gid) 75172237Skevlo{ 76172237Skevlo struct group *gr; 77172237Skevlo static char gids[10]; 78172237Skevlo 79172237Skevlo if ((gr = getgrgid(gid)) == NULL) { 80172237Skevlo (void)snprintf(gids, sizeof(gids), "%u", gid); 81172237Skevlo return (gids); 82172237Skevlo } else 83172237Skevlo return (gr->gr_name); 84172237Skevlo} 85172237Skevlo 8675491Sjedgar/* 8775491Sjedgar * return an ACL corresponding to the permissions 8875491Sjedgar * contained in struct stat 8975491Sjedgar */ 9074465Srwatsonstatic acl_t 9174465Srwatsonacl_from_stat(struct stat sb) 9274465Srwatson{ 9374465Srwatson acl_t acl; 9475491Sjedgar acl_entry_t entry; 9575491Sjedgar acl_permset_t perms; 9674465Srwatson 9775491Sjedgar /* create the ACL */ 9874465Srwatson acl = acl_init(3); 9974465Srwatson if (!acl) 10075491Sjedgar return NULL; 10174465Srwatson 10275491Sjedgar /* First entry: ACL_USER_OBJ */ 10375491Sjedgar if (acl_create_entry(&acl, &entry) == -1) 10475491Sjedgar return NULL; 10575491Sjedgar if (acl_set_tag_type(entry, ACL_USER_OBJ) == -1) 10675491Sjedgar return NULL; 10775491Sjedgar 10875491Sjedgar if (acl_get_permset(entry, &perms) == -1) 10975491Sjedgar return NULL; 11075491Sjedgar if (acl_clear_perms(perms) == -1) 11175491Sjedgar return NULL; 11275491Sjedgar 11375491Sjedgar /* calculate user mode */ 11474465Srwatson if (sb.st_mode & S_IRUSR) 11575491Sjedgar if (acl_add_perm(perms, ACL_READ) == -1) 11675491Sjedgar return NULL; 11774465Srwatson if (sb.st_mode & S_IWUSR) 11875491Sjedgar if (acl_add_perm(perms, ACL_WRITE) == -1) 11975491Sjedgar return NULL; 12074465Srwatson if (sb.st_mode & S_IXUSR) 12175491Sjedgar if (acl_add_perm(perms, ACL_EXECUTE) == -1) 12275491Sjedgar return NULL; 12375491Sjedgar if (acl_set_permset(entry, perms) == -1) 12475491Sjedgar return NULL; 12574465Srwatson 12675491Sjedgar /* Second entry: ACL_GROUP_OBJ */ 12775491Sjedgar if (acl_create_entry(&acl, &entry) == -1) 12875491Sjedgar return NULL; 12975491Sjedgar if (acl_set_tag_type(entry, ACL_GROUP_OBJ) == -1) 13075491Sjedgar return NULL; 13175491Sjedgar 13275491Sjedgar if (acl_get_permset(entry, &perms) == -1) 13375491Sjedgar return NULL; 13475491Sjedgar if (acl_clear_perms(perms) == -1) 13575491Sjedgar return NULL; 13675491Sjedgar 13775491Sjedgar /* calculate group mode */ 13874465Srwatson if (sb.st_mode & S_IRGRP) 13975491Sjedgar if (acl_add_perm(perms, ACL_READ) == -1) 14075491Sjedgar return NULL; 14174465Srwatson if (sb.st_mode & S_IWGRP) 14275491Sjedgar if (acl_add_perm(perms, ACL_WRITE) == -1) 14375491Sjedgar return NULL; 14474465Srwatson if (sb.st_mode & S_IXGRP) 14575491Sjedgar if (acl_add_perm(perms, ACL_EXECUTE) == -1) 14675491Sjedgar return NULL; 14775491Sjedgar if (acl_set_permset(entry, perms) == -1) 14875491Sjedgar return NULL; 14974465Srwatson 15075491Sjedgar /* Third entry: ACL_OTHER */ 15175491Sjedgar if (acl_create_entry(&acl, &entry) == -1) 15275491Sjedgar return NULL; 15375491Sjedgar if (acl_set_tag_type(entry, ACL_OTHER) == -1) 15475491Sjedgar return NULL; 15575491Sjedgar 15675491Sjedgar if (acl_get_permset(entry, &perms) == -1) 15775491Sjedgar return NULL; 15875491Sjedgar if (acl_clear_perms(perms) == -1) 15975491Sjedgar return NULL; 16075491Sjedgar 16175491Sjedgar /* calculate other mode */ 16274465Srwatson if (sb.st_mode & S_IROTH) 16375491Sjedgar if (acl_add_perm(perms, ACL_READ) == -1) 16475491Sjedgar return NULL; 16574465Srwatson if (sb.st_mode & S_IWOTH) 16675491Sjedgar if (acl_add_perm(perms, ACL_WRITE) == -1) 16775491Sjedgar return NULL; 16874465Srwatson if (sb.st_mode & S_IXOTH) 16975491Sjedgar if (acl_add_perm(perms, ACL_EXECUTE) == -1) 17075491Sjedgar return NULL; 17175491Sjedgar if (acl_set_permset(entry, perms) == -1) 17275491Sjedgar return NULL; 17374465Srwatson 17474465Srwatson return(acl); 17574465Srwatson} 17674465Srwatson 17774465Srwatsonstatic int 178196827Straszprint_acl(char *path, acl_type_t type, int hflag, int iflag, int nflag, 179196827Strasz int qflag, int vflag) 18074465Srwatson{ 18174465Srwatson struct stat sb; 18274465Srwatson acl_t acl; 18374465Srwatson char *acl_text; 184196827Strasz int error, flags = 0, ret; 18574465Srwatson 186108450Srwatson if (hflag) 187108450Srwatson error = lstat(path, &sb); 188108450Srwatson else 189108450Srwatson error = stat(path, &sb); 19074465Srwatson if (error == -1) { 191196827Strasz warn("%s: stat() failed", path); 19274465Srwatson return(-1); 19374465Srwatson } 19474465Srwatson 195196827Strasz if (hflag) 196196827Strasz ret = lpathconf(path, _PC_ACL_NFS4); 197196827Strasz else 198196827Strasz ret = pathconf(path, _PC_ACL_NFS4); 199196827Strasz if (ret > 0) { 200196827Strasz if (type == ACL_TYPE_DEFAULT) { 201196827Strasz warnx("%s: there are no default entries in NFSv4 ACLs", 202196827Strasz path); 203196827Strasz return (-1); 204196827Strasz } 205196827Strasz type = ACL_TYPE_NFS4; 206196827Strasz } else if (ret < 0 && errno != EINVAL) { 207196827Strasz warn("%s: pathconf(..., _PC_ACL_NFS4) failed", path); 208196827Strasz return (-1); 209196827Strasz } 210196827Strasz 21174465Srwatson if (more_than_one) 21274465Srwatson printf("\n"); 21374465Srwatson else 21474465Srwatson more_than_one++; 21574465Srwatson 216156681Srwatson if (!qflag) 217172237Skevlo printf("# file: %s\n# owner: %s\n# group: %s\n", path, 218172237Skevlo getuname(sb.st_uid), getgname(sb.st_gid)); 21974465Srwatson 220108450Srwatson if (hflag) 221108450Srwatson acl = acl_get_link_np(path, type); 222108450Srwatson else 223108450Srwatson acl = acl_get_file(path, type); 22474465Srwatson if (!acl) { 22574465Srwatson if (errno != EOPNOTSUPP) { 22674465Srwatson warn("%s", path); 22774465Srwatson return(-1); 22874465Srwatson } 22974465Srwatson errno = 0; 230196827Strasz if (type == ACL_TYPE_DEFAULT) 23174465Srwatson return(0); 23274465Srwatson acl = acl_from_stat(sb); 23374465Srwatson if (!acl) { 234196827Strasz warn("%s: acl_from_stat() failed", path); 23574465Srwatson return(-1); 23674465Srwatson } 23774465Srwatson } 23874465Srwatson 239196827Strasz if (iflag) 240196827Strasz flags |= ACL_TEXT_APPEND_ID; 241196827Strasz 242196827Strasz if (nflag) 243196827Strasz flags |= ACL_TEXT_NUMERIC_IDS; 244196827Strasz 245196827Strasz if (vflag) 246196827Strasz flags |= ACL_TEXT_VERBOSE; 247196827Strasz 248196827Strasz acl_text = acl_to_text_np(acl, 0, flags); 24974465Srwatson if (!acl_text) { 250196827Strasz warn("%s: acl_to_text_np() failed", path); 25174465Srwatson return(-1); 25274465Srwatson } 25374465Srwatson 25474465Srwatson printf("%s", acl_text); 25574465Srwatson 25691083Smarkm (void)acl_free(acl); 25791083Smarkm (void)acl_free(acl_text); 25874465Srwatson 25974465Srwatson return(0); 26074465Srwatson} 26174465Srwatson 26274465Srwatsonstatic int 263196827Straszprint_acl_from_stdin(acl_type_t type, int hflag, int iflag, int nflag, 264196827Strasz int qflag, int vflag) 26574465Srwatson{ 266106388Stjr char *p, pathname[PATH_MAX]; 26774465Srwatson int carried_error = 0; 26874465Srwatson 26976875Skris while (fgets(pathname, (int)sizeof(pathname), stdin)) { 270106388Stjr if ((p = strchr(pathname, '\n')) != NULL) 271106388Stjr *p = '\0'; 272196827Strasz if (print_acl(pathname, type, hflag, iflag, nflag, 273196827Strasz qflag, vflag) == -1) { 27474465Srwatson carried_error = -1; 27574465Srwatson } 27674465Srwatson } 27774465Srwatson 27874465Srwatson return(carried_error); 27974465Srwatson} 28074465Srwatson 28174465Srwatsonint 28274465Srwatsonmain(int argc, char *argv[]) 28374465Srwatson{ 28474465Srwatson acl_type_t type = ACL_TYPE_ACCESS; 28574465Srwatson int carried_error = 0; 28674465Srwatson int ch, error, i; 287196827Strasz int hflag, iflag, qflag, nflag, vflag; 28874465Srwatson 289108450Srwatson hflag = 0; 290196827Strasz iflag = 0; 291156681Srwatson qflag = 0; 292196827Strasz nflag = 0; 293196827Strasz vflag = 0; 294196827Strasz while ((ch = getopt(argc, argv, "dhinqv")) != -1) 29574465Srwatson switch(ch) { 29674465Srwatson case 'd': 29774465Srwatson type = ACL_TYPE_DEFAULT; 29874465Srwatson break; 299108450Srwatson case 'h': 300108450Srwatson hflag = 1; 301108450Srwatson break; 302196827Strasz case 'i': 303196827Strasz iflag = 1; 304196827Strasz break; 305196827Strasz case 'n': 306196827Strasz nflag = 1; 307196827Strasz break; 308156681Srwatson case 'q': 309156681Srwatson qflag = 1; 310156681Srwatson break; 311196827Strasz case 'v': 312196827Strasz vflag = 1; 313196827Strasz break; 31474465Srwatson default: 31574465Srwatson usage(); 31674465Srwatson return(-1); 31774465Srwatson } 31874465Srwatson argc -= optind; 31974465Srwatson argv += optind; 32074465Srwatson 32174465Srwatson if (argc == 0) { 322196827Strasz error = print_acl_from_stdin(type, hflag, iflag, nflag, 323196827Strasz qflag, vflag); 324106388Stjr return(error ? 1 : 0); 32574465Srwatson } 32674465Srwatson 32774465Srwatson for (i = 0; i < argc; i++) { 32874465Srwatson if (!strcmp(argv[i], "-")) { 329196827Strasz error = print_acl_from_stdin(type, hflag, iflag, nflag, 330196827Strasz qflag, vflag); 33174465Srwatson if (error == -1) 33274465Srwatson carried_error = -1; 33374465Srwatson } else { 334196827Strasz error = print_acl(argv[i], type, hflag, iflag, nflag, 335196827Strasz qflag, vflag); 33674465Srwatson if (error == -1) 33774465Srwatson carried_error = -1; 33874465Srwatson } 33974465Srwatson } 34074465Srwatson 341106388Stjr return(carried_error ? 1 : 0); 34274465Srwatson} 343