143960f15SRobert Watson /*- 28051fddeSRobert Watson * Copyright (c) 1999, 2001, 2002 Robert N M Watson 343960f15SRobert Watson * All rights reserved. 443960f15SRobert Watson * 59331ef53SRobert Watson * This software was developed by Robert Watson for the TrustedBSD Project. 69331ef53SRobert Watson * 743960f15SRobert Watson * Redistribution and use in source and binary forms, with or without 843960f15SRobert Watson * modification, are permitted provided that the following conditions 943960f15SRobert Watson * are met: 1043960f15SRobert Watson * 1. Redistributions of source code must retain the above copyright 1143960f15SRobert Watson * notice, this list of conditions and the following disclaimer. 1243960f15SRobert Watson * 2. Redistributions in binary form must reproduce the above copyright 1343960f15SRobert Watson * notice, this list of conditions and the following disclaimer in the 1443960f15SRobert Watson * documentation and/or other materials provided with the distribution. 1543960f15SRobert Watson * 1643960f15SRobert Watson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1743960f15SRobert Watson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1843960f15SRobert Watson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1943960f15SRobert Watson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2043960f15SRobert Watson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2143960f15SRobert Watson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2243960f15SRobert Watson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2343960f15SRobert Watson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2443960f15SRobert Watson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2543960f15SRobert Watson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2643960f15SRobert Watson * SUCH DAMAGE. 2743960f15SRobert Watson */ 2843960f15SRobert Watson /* 2943960f15SRobert Watson * getfacl -- POSIX.1e utility to extract ACLs from files and directories 3043960f15SRobert Watson * and send the results to stdout 3143960f15SRobert Watson */ 3243960f15SRobert Watson 335eb43ac2SDavid E. O'Brien 345eb43ac2SDavid E. O'Brien #include <sys/cdefs.h> 355eb43ac2SDavid E. O'Brien __FBSDID("$FreeBSD$"); 365eb43ac2SDavid E. O'Brien 3743960f15SRobert Watson #include <sys/types.h> 3843960f15SRobert Watson #include <sys/param.h> 3943960f15SRobert Watson #include <sys/acl.h> 4043960f15SRobert Watson #include <sys/stat.h> 415eb43ac2SDavid E. O'Brien 4243960f15SRobert Watson #include <err.h> 4343960f15SRobert Watson #include <errno.h> 44c5771451SKevin Lo #include <grp.h> 45c5771451SKevin Lo #include <pwd.h> 4643960f15SRobert Watson #include <stdio.h> 477a832d43SChris D. Faulhaber #include <stdlib.h> 4828bf3202SKris Kennaway #include <string.h> 4943960f15SRobert Watson #include <unistd.h> 5043960f15SRobert Watson 51ae824d80SEd Schouten static int more_than_one = 0; 5243960f15SRobert Watson 5343960f15SRobert Watson static void 5443960f15SRobert Watson usage(void) 5543960f15SRobert Watson { 5643960f15SRobert Watson 5783bd4cd0SEdward Tomasz Napierala fprintf(stderr, "getfacl [-dhnqv] [file ...]\n"); 5843960f15SRobert Watson } 5943960f15SRobert Watson 60c5771451SKevin Lo static char * 61c5771451SKevin Lo getuname(uid_t uid) 62c5771451SKevin Lo { 63c5771451SKevin Lo struct passwd *pw; 64c5771451SKevin Lo static char uids[10]; 65c5771451SKevin Lo 66c5771451SKevin Lo if ((pw = getpwuid(uid)) == NULL) { 67c5771451SKevin Lo (void)snprintf(uids, sizeof(uids), "%u", uid); 68c5771451SKevin Lo return (uids); 69c5771451SKevin Lo } else 70c5771451SKevin Lo return (pw->pw_name); 71c5771451SKevin Lo } 72c5771451SKevin Lo 73c5771451SKevin Lo static char * 74c5771451SKevin Lo getgname(gid_t gid) 75c5771451SKevin Lo { 76c5771451SKevin Lo struct group *gr; 77c5771451SKevin Lo static char gids[10]; 78c5771451SKevin Lo 79c5771451SKevin Lo if ((gr = getgrgid(gid)) == NULL) { 80c5771451SKevin Lo (void)snprintf(gids, sizeof(gids), "%u", gid); 81c5771451SKevin Lo return (gids); 82c5771451SKevin Lo } else 83c5771451SKevin Lo return (gr->gr_name); 84c5771451SKevin Lo } 85c5771451SKevin Lo 867a832d43SChris D. Faulhaber /* 877a832d43SChris D. Faulhaber * return an ACL corresponding to the permissions 887a832d43SChris D. Faulhaber * contained in struct stat 897a832d43SChris D. Faulhaber */ 9043960f15SRobert Watson static acl_t 9143960f15SRobert Watson acl_from_stat(struct stat sb) 9243960f15SRobert Watson { 9343960f15SRobert Watson acl_t acl; 947a832d43SChris D. Faulhaber acl_entry_t entry; 957a832d43SChris D. Faulhaber acl_permset_t perms; 9643960f15SRobert Watson 977a832d43SChris D. Faulhaber /* create the ACL */ 9843960f15SRobert Watson acl = acl_init(3); 9943960f15SRobert Watson if (!acl) 1007a832d43SChris D. Faulhaber return NULL; 10143960f15SRobert Watson 1027a832d43SChris D. Faulhaber /* First entry: ACL_USER_OBJ */ 1037a832d43SChris D. Faulhaber if (acl_create_entry(&acl, &entry) == -1) 1047a832d43SChris D. Faulhaber return NULL; 1057a832d43SChris D. Faulhaber if (acl_set_tag_type(entry, ACL_USER_OBJ) == -1) 1067a832d43SChris D. Faulhaber return NULL; 1077a832d43SChris D. Faulhaber 1087a832d43SChris D. Faulhaber if (acl_get_permset(entry, &perms) == -1) 1097a832d43SChris D. Faulhaber return NULL; 1107a832d43SChris D. Faulhaber if (acl_clear_perms(perms) == -1) 1117a832d43SChris D. Faulhaber return NULL; 1127a832d43SChris D. Faulhaber 1137a832d43SChris D. Faulhaber /* calculate user mode */ 11443960f15SRobert Watson if (sb.st_mode & S_IRUSR) 1157a832d43SChris D. Faulhaber if (acl_add_perm(perms, ACL_READ) == -1) 1167a832d43SChris D. Faulhaber return NULL; 11743960f15SRobert Watson if (sb.st_mode & S_IWUSR) 1187a832d43SChris D. Faulhaber if (acl_add_perm(perms, ACL_WRITE) == -1) 1197a832d43SChris D. Faulhaber return NULL; 12043960f15SRobert Watson if (sb.st_mode & S_IXUSR) 1217a832d43SChris D. Faulhaber if (acl_add_perm(perms, ACL_EXECUTE) == -1) 1227a832d43SChris D. Faulhaber return NULL; 1237a832d43SChris D. Faulhaber if (acl_set_permset(entry, perms) == -1) 1247a832d43SChris D. Faulhaber return NULL; 12543960f15SRobert Watson 1267a832d43SChris D. Faulhaber /* Second entry: ACL_GROUP_OBJ */ 1277a832d43SChris D. Faulhaber if (acl_create_entry(&acl, &entry) == -1) 1287a832d43SChris D. Faulhaber return NULL; 1297a832d43SChris D. Faulhaber if (acl_set_tag_type(entry, ACL_GROUP_OBJ) == -1) 1307a832d43SChris D. Faulhaber return NULL; 1317a832d43SChris D. Faulhaber 1327a832d43SChris D. Faulhaber if (acl_get_permset(entry, &perms) == -1) 1337a832d43SChris D. Faulhaber return NULL; 1347a832d43SChris D. Faulhaber if (acl_clear_perms(perms) == -1) 1357a832d43SChris D. Faulhaber return NULL; 1367a832d43SChris D. Faulhaber 1377a832d43SChris D. Faulhaber /* calculate group mode */ 13843960f15SRobert Watson if (sb.st_mode & S_IRGRP) 1397a832d43SChris D. Faulhaber if (acl_add_perm(perms, ACL_READ) == -1) 1407a832d43SChris D. Faulhaber return NULL; 14143960f15SRobert Watson if (sb.st_mode & S_IWGRP) 1427a832d43SChris D. Faulhaber if (acl_add_perm(perms, ACL_WRITE) == -1) 1437a832d43SChris D. Faulhaber return NULL; 14443960f15SRobert Watson if (sb.st_mode & S_IXGRP) 1457a832d43SChris D. Faulhaber if (acl_add_perm(perms, ACL_EXECUTE) == -1) 1467a832d43SChris D. Faulhaber return NULL; 1477a832d43SChris D. Faulhaber if (acl_set_permset(entry, perms) == -1) 1487a832d43SChris D. Faulhaber return NULL; 14943960f15SRobert Watson 1507a832d43SChris D. Faulhaber /* Third entry: ACL_OTHER */ 1517a832d43SChris D. Faulhaber if (acl_create_entry(&acl, &entry) == -1) 1527a832d43SChris D. Faulhaber return NULL; 1537a832d43SChris D. Faulhaber if (acl_set_tag_type(entry, ACL_OTHER) == -1) 1547a832d43SChris D. Faulhaber return NULL; 1557a832d43SChris D. Faulhaber 1567a832d43SChris D. Faulhaber if (acl_get_permset(entry, &perms) == -1) 1577a832d43SChris D. Faulhaber return NULL; 1587a832d43SChris D. Faulhaber if (acl_clear_perms(perms) == -1) 1597a832d43SChris D. Faulhaber return NULL; 1607a832d43SChris D. Faulhaber 1617a832d43SChris D. Faulhaber /* calculate other mode */ 16243960f15SRobert Watson if (sb.st_mode & S_IROTH) 1637a832d43SChris D. Faulhaber if (acl_add_perm(perms, ACL_READ) == -1) 1647a832d43SChris D. Faulhaber return NULL; 16543960f15SRobert Watson if (sb.st_mode & S_IWOTH) 1667a832d43SChris D. Faulhaber if (acl_add_perm(perms, ACL_WRITE) == -1) 1677a832d43SChris D. Faulhaber return NULL; 16843960f15SRobert Watson if (sb.st_mode & S_IXOTH) 1697a832d43SChris D. Faulhaber if (acl_add_perm(perms, ACL_EXECUTE) == -1) 1707a832d43SChris D. Faulhaber return NULL; 1717a832d43SChris D. Faulhaber if (acl_set_permset(entry, perms) == -1) 1727a832d43SChris D. Faulhaber return NULL; 17343960f15SRobert Watson 17443960f15SRobert Watson return(acl); 17543960f15SRobert Watson } 17643960f15SRobert Watson 17743960f15SRobert Watson static int 17883bd4cd0SEdward Tomasz Napierala print_acl(char *path, acl_type_t type, int hflag, int iflag, int nflag, 17983bd4cd0SEdward Tomasz Napierala int qflag, int vflag) 18043960f15SRobert Watson { 18143960f15SRobert Watson struct stat sb; 18243960f15SRobert Watson acl_t acl; 18343960f15SRobert Watson char *acl_text; 18483bd4cd0SEdward Tomasz Napierala int error, flags = 0, ret; 18543960f15SRobert Watson 1868051fddeSRobert Watson if (hflag) 1878051fddeSRobert Watson error = lstat(path, &sb); 1888051fddeSRobert Watson else 18943960f15SRobert Watson error = stat(path, &sb); 19043960f15SRobert Watson if (error == -1) { 19183bd4cd0SEdward Tomasz Napierala warn("%s: stat() failed", path); 19283bd4cd0SEdward Tomasz Napierala return(-1); 19383bd4cd0SEdward Tomasz Napierala } 19483bd4cd0SEdward Tomasz Napierala 19583bd4cd0SEdward Tomasz Napierala if (hflag) 19683bd4cd0SEdward Tomasz Napierala ret = lpathconf(path, _PC_ACL_NFS4); 19783bd4cd0SEdward Tomasz Napierala else 19883bd4cd0SEdward Tomasz Napierala ret = pathconf(path, _PC_ACL_NFS4); 19983bd4cd0SEdward Tomasz Napierala if (ret > 0) { 20083bd4cd0SEdward Tomasz Napierala if (type == ACL_TYPE_DEFAULT) { 20183bd4cd0SEdward Tomasz Napierala warnx("%s: there are no default entries in NFSv4 ACLs", 20283bd4cd0SEdward Tomasz Napierala path); 20383bd4cd0SEdward Tomasz Napierala return (-1); 20483bd4cd0SEdward Tomasz Napierala } 20583bd4cd0SEdward Tomasz Napierala type = ACL_TYPE_NFS4; 20683bd4cd0SEdward Tomasz Napierala } else if (ret < 0 && errno != EINVAL) { 20783bd4cd0SEdward Tomasz Napierala warn("%s: pathconf(..., _PC_ACL_NFS4) failed", path); 20843960f15SRobert Watson return (-1); 20943960f15SRobert Watson } 21043960f15SRobert Watson 21143960f15SRobert Watson if (more_than_one) 21243960f15SRobert Watson printf("\n"); 21343960f15SRobert Watson else 21443960f15SRobert Watson more_than_one++; 21543960f15SRobert Watson 216f9a86e37SRobert Watson if (!qflag) 217c5771451SKevin Lo printf("# file: %s\n# owner: %s\n# group: %s\n", path, 218c5771451SKevin Lo getuname(sb.st_uid), getgname(sb.st_gid)); 21943960f15SRobert Watson 2208051fddeSRobert Watson if (hflag) 2218051fddeSRobert Watson acl = acl_get_link_np(path, type); 2228051fddeSRobert Watson else 22343960f15SRobert Watson acl = acl_get_file(path, type); 22443960f15SRobert Watson if (!acl) { 22543960f15SRobert Watson if (errno != EOPNOTSUPP) { 22643960f15SRobert Watson warn("%s", path); 22743960f15SRobert Watson return(-1); 22843960f15SRobert Watson } 22943960f15SRobert Watson errno = 0; 23083bd4cd0SEdward Tomasz Napierala if (type == ACL_TYPE_DEFAULT) 23143960f15SRobert Watson return(0); 23243960f15SRobert Watson acl = acl_from_stat(sb); 23343960f15SRobert Watson if (!acl) { 23483bd4cd0SEdward Tomasz Napierala warn("%s: acl_from_stat() failed", path); 23543960f15SRobert Watson return(-1); 23643960f15SRobert Watson } 23743960f15SRobert Watson } 23843960f15SRobert Watson 23983bd4cd0SEdward Tomasz Napierala if (iflag) 24083bd4cd0SEdward Tomasz Napierala flags |= ACL_TEXT_APPEND_ID; 24183bd4cd0SEdward Tomasz Napierala 24283bd4cd0SEdward Tomasz Napierala if (nflag) 24383bd4cd0SEdward Tomasz Napierala flags |= ACL_TEXT_NUMERIC_IDS; 24483bd4cd0SEdward Tomasz Napierala 24583bd4cd0SEdward Tomasz Napierala if (vflag) 24683bd4cd0SEdward Tomasz Napierala flags |= ACL_TEXT_VERBOSE; 24783bd4cd0SEdward Tomasz Napierala 24883bd4cd0SEdward Tomasz Napierala acl_text = acl_to_text_np(acl, 0, flags); 24943960f15SRobert Watson if (!acl_text) { 25083bd4cd0SEdward Tomasz Napierala warn("%s: acl_to_text_np() failed", path); 25143960f15SRobert Watson return(-1); 25243960f15SRobert Watson } 25343960f15SRobert Watson 25443960f15SRobert Watson printf("%s", acl_text); 25543960f15SRobert Watson 256fab912dfSMark Murray (void)acl_free(acl); 257fab912dfSMark Murray (void)acl_free(acl_text); 25843960f15SRobert Watson 25943960f15SRobert Watson return(0); 26043960f15SRobert Watson } 26143960f15SRobert Watson 26243960f15SRobert Watson static int 26383bd4cd0SEdward Tomasz Napierala print_acl_from_stdin(acl_type_t type, int hflag, int iflag, int nflag, 26483bd4cd0SEdward Tomasz Napierala int qflag, int vflag) 26543960f15SRobert Watson { 2664e65ab95STim J. Robbins char *p, pathname[PATH_MAX]; 26743960f15SRobert Watson int carried_error = 0; 26843960f15SRobert Watson 26928bf3202SKris Kennaway while (fgets(pathname, (int)sizeof(pathname), stdin)) { 2704e65ab95STim J. Robbins if ((p = strchr(pathname, '\n')) != NULL) 2714e65ab95STim J. Robbins *p = '\0'; 27283bd4cd0SEdward Tomasz Napierala if (print_acl(pathname, type, hflag, iflag, nflag, 27383bd4cd0SEdward Tomasz Napierala qflag, vflag) == -1) { 27443960f15SRobert Watson carried_error = -1; 27543960f15SRobert Watson } 27643960f15SRobert Watson } 27743960f15SRobert Watson 27843960f15SRobert Watson return(carried_error); 27943960f15SRobert Watson } 28043960f15SRobert Watson 28143960f15SRobert Watson int 28243960f15SRobert Watson main(int argc, char *argv[]) 28343960f15SRobert Watson { 28443960f15SRobert Watson acl_type_t type = ACL_TYPE_ACCESS; 28543960f15SRobert Watson int carried_error = 0; 28643960f15SRobert Watson int ch, error, i; 28783bd4cd0SEdward Tomasz Napierala int hflag, iflag, qflag, nflag, vflag; 28843960f15SRobert Watson 2898051fddeSRobert Watson hflag = 0; 29083bd4cd0SEdward Tomasz Napierala iflag = 0; 291f9a86e37SRobert Watson qflag = 0; 29283bd4cd0SEdward Tomasz Napierala nflag = 0; 29383bd4cd0SEdward Tomasz Napierala vflag = 0; 29483bd4cd0SEdward Tomasz Napierala while ((ch = getopt(argc, argv, "dhinqv")) != -1) 29543960f15SRobert Watson switch(ch) { 29643960f15SRobert Watson case 'd': 29743960f15SRobert Watson type = ACL_TYPE_DEFAULT; 29843960f15SRobert Watson break; 2998051fddeSRobert Watson case 'h': 3008051fddeSRobert Watson hflag = 1; 3018051fddeSRobert Watson break; 30283bd4cd0SEdward Tomasz Napierala case 'i': 30383bd4cd0SEdward Tomasz Napierala iflag = 1; 30483bd4cd0SEdward Tomasz Napierala break; 30583bd4cd0SEdward Tomasz Napierala case 'n': 30683bd4cd0SEdward Tomasz Napierala nflag = 1; 30783bd4cd0SEdward Tomasz Napierala break; 308f9a86e37SRobert Watson case 'q': 309f9a86e37SRobert Watson qflag = 1; 310f9a86e37SRobert Watson break; 31183bd4cd0SEdward Tomasz Napierala case 'v': 31283bd4cd0SEdward Tomasz Napierala vflag = 1; 31383bd4cd0SEdward Tomasz Napierala break; 31443960f15SRobert Watson default: 31543960f15SRobert Watson usage(); 31643960f15SRobert Watson return(-1); 31743960f15SRobert Watson } 31843960f15SRobert Watson argc -= optind; 31943960f15SRobert Watson argv += optind; 32043960f15SRobert Watson 32143960f15SRobert Watson if (argc == 0) { 32283bd4cd0SEdward Tomasz Napierala error = print_acl_from_stdin(type, hflag, iflag, nflag, 32383bd4cd0SEdward Tomasz Napierala qflag, vflag); 3244e65ab95STim J. Robbins return(error ? 1 : 0); 32543960f15SRobert Watson } 32643960f15SRobert Watson 32743960f15SRobert Watson for (i = 0; i < argc; i++) { 32843960f15SRobert Watson if (!strcmp(argv[i], "-")) { 32983bd4cd0SEdward Tomasz Napierala error = print_acl_from_stdin(type, hflag, iflag, nflag, 33083bd4cd0SEdward Tomasz Napierala qflag, vflag); 33143960f15SRobert Watson if (error == -1) 33243960f15SRobert Watson carried_error = -1; 33343960f15SRobert Watson } else { 33483bd4cd0SEdward Tomasz Napierala error = print_acl(argv[i], type, hflag, iflag, nflag, 33583bd4cd0SEdward Tomasz Napierala qflag, vflag); 33643960f15SRobert Watson if (error == -1) 33743960f15SRobert Watson carried_error = -1; 33843960f15SRobert Watson } 33943960f15SRobert Watson } 34043960f15SRobert Watson 3414e65ab95STim J. Robbins return(carried_error ? 1 : 0); 34243960f15SRobert Watson } 343