1*fb222b15Sjoerg /* $NetBSD: getfacl.c,v 1.2 2020/05/22 01:28:00 joerg Exp $ */
29aa2a9c3Schristos
39aa2a9c3Schristos /*-
49aa2a9c3Schristos * Copyright (c) 1999, 2001, 2002 Robert N M Watson
59aa2a9c3Schristos * All rights reserved.
69aa2a9c3Schristos *
79aa2a9c3Schristos * This software was developed by Robert Watson for the TrustedBSD Project.
89aa2a9c3Schristos *
99aa2a9c3Schristos * Redistribution and use in source and binary forms, with or without
109aa2a9c3Schristos * modification, are permitted provided that the following conditions
119aa2a9c3Schristos * are met:
129aa2a9c3Schristos * 1. Redistributions of source code must retain the above copyright
139aa2a9c3Schristos * notice, this list of conditions and the following disclaimer.
149aa2a9c3Schristos * 2. Redistributions in binary form must reproduce the above copyright
159aa2a9c3Schristos * notice, this list of conditions and the following disclaimer in the
169aa2a9c3Schristos * documentation and/or other materials provided with the distribution.
179aa2a9c3Schristos *
189aa2a9c3Schristos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
199aa2a9c3Schristos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
209aa2a9c3Schristos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
219aa2a9c3Schristos * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
229aa2a9c3Schristos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
239aa2a9c3Schristos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
249aa2a9c3Schristos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
259aa2a9c3Schristos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
269aa2a9c3Schristos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
279aa2a9c3Schristos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
289aa2a9c3Schristos * SUCH DAMAGE.
299aa2a9c3Schristos */
309aa2a9c3Schristos /*
319aa2a9c3Schristos * getfacl -- POSIX.1e utility to extract ACLs from files and directories
329aa2a9c3Schristos * and send the results to stdout
339aa2a9c3Schristos */
349aa2a9c3Schristos
359aa2a9c3Schristos
369aa2a9c3Schristos #include <sys/cdefs.h>
379aa2a9c3Schristos #if 0
389aa2a9c3Schristos __FBSDID("$FreeBSD: head/bin/getfacl/getfacl.c 340014 2018-11-01 17:45:29Z markj $");
399aa2a9c3Schristos #else
40*fb222b15Sjoerg __RCSID("$NetBSD: getfacl.c,v 1.2 2020/05/22 01:28:00 joerg Exp $");
419aa2a9c3Schristos #endif
429aa2a9c3Schristos
439aa2a9c3Schristos #include <sys/types.h>
449aa2a9c3Schristos #include <sys/param.h>
459aa2a9c3Schristos #include <sys/acl.h>
469aa2a9c3Schristos #include <sys/stat.h>
479aa2a9c3Schristos
489aa2a9c3Schristos #include <err.h>
499aa2a9c3Schristos #include <errno.h>
509aa2a9c3Schristos #include <grp.h>
519aa2a9c3Schristos #include <pwd.h>
529aa2a9c3Schristos #include <stdio.h>
539aa2a9c3Schristos #include <stdlib.h>
549aa2a9c3Schristos #include <string.h>
559aa2a9c3Schristos #include <unistd.h>
569aa2a9c3Schristos
579aa2a9c3Schristos static int more_than_one = 0;
589aa2a9c3Schristos
599aa2a9c3Schristos static __dead void
usage(void)609aa2a9c3Schristos usage(void)
619aa2a9c3Schristos {
629aa2a9c3Schristos
639aa2a9c3Schristos fprintf(stderr, "Usage: %s [-dhnqv] [file ...]\n", getprogname());
64*fb222b15Sjoerg exit(1);
659aa2a9c3Schristos }
669aa2a9c3Schristos
679aa2a9c3Schristos static char *
getuname(uid_t uid)689aa2a9c3Schristos getuname(uid_t uid)
699aa2a9c3Schristos {
709aa2a9c3Schristos struct passwd *pw;
719aa2a9c3Schristos static char uids[10];
729aa2a9c3Schristos
739aa2a9c3Schristos if ((pw = getpwuid(uid)) == NULL) {
749aa2a9c3Schristos (void)snprintf(uids, sizeof(uids), "%u", uid);
759aa2a9c3Schristos return (uids);
769aa2a9c3Schristos } else
779aa2a9c3Schristos return (pw->pw_name);
789aa2a9c3Schristos }
799aa2a9c3Schristos
809aa2a9c3Schristos static char *
getgname(gid_t gid)819aa2a9c3Schristos getgname(gid_t gid)
829aa2a9c3Schristos {
839aa2a9c3Schristos struct group *gr;
849aa2a9c3Schristos static char gids[10];
859aa2a9c3Schristos
869aa2a9c3Schristos if ((gr = getgrgid(gid)) == NULL) {
879aa2a9c3Schristos (void)snprintf(gids, sizeof(gids), "%u", gid);
889aa2a9c3Schristos return (gids);
899aa2a9c3Schristos } else
909aa2a9c3Schristos return (gr->gr_name);
919aa2a9c3Schristos }
929aa2a9c3Schristos
939aa2a9c3Schristos /*
949aa2a9c3Schristos * return an ACL corresponding to the permissions
959aa2a9c3Schristos * contained in struct stat
969aa2a9c3Schristos */
979aa2a9c3Schristos static acl_t
acl_from_stat(const struct stat * sb)989aa2a9c3Schristos acl_from_stat(const struct stat *sb)
999aa2a9c3Schristos {
1009aa2a9c3Schristos acl_t acl;
1019aa2a9c3Schristos acl_entry_t entry;
1029aa2a9c3Schristos acl_permset_t perms;
1039aa2a9c3Schristos
1049aa2a9c3Schristos /* create the ACL */
1059aa2a9c3Schristos acl = acl_init(3);
1069aa2a9c3Schristos if (!acl)
1079aa2a9c3Schristos return NULL;
1089aa2a9c3Schristos
1099aa2a9c3Schristos /* First entry: ACL_USER_OBJ */
1109aa2a9c3Schristos if (acl_create_entry(&acl, &entry) == -1)
1119aa2a9c3Schristos return NULL;
1129aa2a9c3Schristos if (acl_set_tag_type(entry, ACL_USER_OBJ) == -1)
1139aa2a9c3Schristos return NULL;
1149aa2a9c3Schristos
1159aa2a9c3Schristos if (acl_get_permset(entry, &perms) == -1)
1169aa2a9c3Schristos return NULL;
1179aa2a9c3Schristos if (acl_clear_perms(perms) == -1)
1189aa2a9c3Schristos return NULL;
1199aa2a9c3Schristos
1209aa2a9c3Schristos /* calculate user mode */
1219aa2a9c3Schristos if (sb->st_mode & S_IRUSR)
1229aa2a9c3Schristos if (acl_add_perm(perms, ACL_READ) == -1)
1239aa2a9c3Schristos return NULL;
1249aa2a9c3Schristos if (sb->st_mode & S_IWUSR)
1259aa2a9c3Schristos if (acl_add_perm(perms, ACL_WRITE) == -1)
1269aa2a9c3Schristos return NULL;
1279aa2a9c3Schristos if (sb->st_mode & S_IXUSR)
1289aa2a9c3Schristos if (acl_add_perm(perms, ACL_EXECUTE) == -1)
1299aa2a9c3Schristos return NULL;
1309aa2a9c3Schristos if (acl_set_permset(entry, perms) == -1)
1319aa2a9c3Schristos return NULL;
1329aa2a9c3Schristos
1339aa2a9c3Schristos /* Second entry: ACL_GROUP_OBJ */
1349aa2a9c3Schristos if (acl_create_entry(&acl, &entry) == -1)
1359aa2a9c3Schristos return NULL;
1369aa2a9c3Schristos if (acl_set_tag_type(entry, ACL_GROUP_OBJ) == -1)
1379aa2a9c3Schristos return NULL;
1389aa2a9c3Schristos
1399aa2a9c3Schristos if (acl_get_permset(entry, &perms) == -1)
1409aa2a9c3Schristos return NULL;
1419aa2a9c3Schristos if (acl_clear_perms(perms) == -1)
1429aa2a9c3Schristos return NULL;
1439aa2a9c3Schristos
1449aa2a9c3Schristos /* calculate group mode */
1459aa2a9c3Schristos if (sb->st_mode & S_IRGRP)
1469aa2a9c3Schristos if (acl_add_perm(perms, ACL_READ) == -1)
1479aa2a9c3Schristos return NULL;
1489aa2a9c3Schristos if (sb->st_mode & S_IWGRP)
1499aa2a9c3Schristos if (acl_add_perm(perms, ACL_WRITE) == -1)
1509aa2a9c3Schristos return NULL;
1519aa2a9c3Schristos if (sb->st_mode & S_IXGRP)
1529aa2a9c3Schristos if (acl_add_perm(perms, ACL_EXECUTE) == -1)
1539aa2a9c3Schristos return NULL;
1549aa2a9c3Schristos if (acl_set_permset(entry, perms) == -1)
1559aa2a9c3Schristos return NULL;
1569aa2a9c3Schristos
1579aa2a9c3Schristos /* Third entry: ACL_OTHER */
1589aa2a9c3Schristos if (acl_create_entry(&acl, &entry) == -1)
1599aa2a9c3Schristos return NULL;
1609aa2a9c3Schristos if (acl_set_tag_type(entry, ACL_OTHER) == -1)
1619aa2a9c3Schristos return NULL;
1629aa2a9c3Schristos
1639aa2a9c3Schristos if (acl_get_permset(entry, &perms) == -1)
1649aa2a9c3Schristos return NULL;
1659aa2a9c3Schristos if (acl_clear_perms(perms) == -1)
1669aa2a9c3Schristos return NULL;
1679aa2a9c3Schristos
1689aa2a9c3Schristos /* calculate other mode */
1699aa2a9c3Schristos if (sb->st_mode & S_IROTH)
1709aa2a9c3Schristos if (acl_add_perm(perms, ACL_READ) == -1)
1719aa2a9c3Schristos return NULL;
1729aa2a9c3Schristos if (sb->st_mode & S_IWOTH)
1739aa2a9c3Schristos if (acl_add_perm(perms, ACL_WRITE) == -1)
1749aa2a9c3Schristos return NULL;
1759aa2a9c3Schristos if (sb->st_mode & S_IXOTH)
1769aa2a9c3Schristos if (acl_add_perm(perms, ACL_EXECUTE) == -1)
1779aa2a9c3Schristos return NULL;
1789aa2a9c3Schristos if (acl_set_permset(entry, perms) == -1)
1799aa2a9c3Schristos return NULL;
1809aa2a9c3Schristos
1819aa2a9c3Schristos return(acl);
1829aa2a9c3Schristos }
1839aa2a9c3Schristos
1849aa2a9c3Schristos static int
print_acl(char * path,acl_type_t type,int hflag,int iflag,int nflag,int qflag,int vflag)1859aa2a9c3Schristos print_acl(char *path, acl_type_t type, int hflag, int iflag, int nflag,
1869aa2a9c3Schristos int qflag, int vflag)
1879aa2a9c3Schristos {
1889aa2a9c3Schristos struct stat sb;
1899aa2a9c3Schristos acl_t acl;
1909aa2a9c3Schristos char *acl_text;
1919aa2a9c3Schristos int error, flags = 0, ret;
1929aa2a9c3Schristos
1939aa2a9c3Schristos if (hflag)
1949aa2a9c3Schristos error = lstat(path, &sb);
1959aa2a9c3Schristos else
1969aa2a9c3Schristos error = stat(path, &sb);
1979aa2a9c3Schristos if (error == -1) {
1989aa2a9c3Schristos warn("%s: stat() failed", path);
1999aa2a9c3Schristos return(-1);
2009aa2a9c3Schristos }
2019aa2a9c3Schristos
2029aa2a9c3Schristos if (hflag)
2039aa2a9c3Schristos ret = lpathconf(path, _PC_ACL_NFS4);
2049aa2a9c3Schristos else
2059aa2a9c3Schristos ret = pathconf(path, _PC_ACL_NFS4);
2069aa2a9c3Schristos if (ret > 0) {
2079aa2a9c3Schristos if (type == ACL_TYPE_DEFAULT) {
2089aa2a9c3Schristos warnx("%s: there are no default entries in NFSv4 ACLs",
2099aa2a9c3Schristos path);
2109aa2a9c3Schristos return (-1);
2119aa2a9c3Schristos }
2129aa2a9c3Schristos type = ACL_TYPE_NFS4;
2139aa2a9c3Schristos } else if (ret < 0 && errno != EINVAL) {
2149aa2a9c3Schristos warn("%s: pathconf(..., _PC_ACL_NFS4) failed", path);
2159aa2a9c3Schristos return (-1);
2169aa2a9c3Schristos }
2179aa2a9c3Schristos
2189aa2a9c3Schristos if (more_than_one)
2199aa2a9c3Schristos printf("\n");
2209aa2a9c3Schristos else
2219aa2a9c3Schristos more_than_one++;
2229aa2a9c3Schristos
2239aa2a9c3Schristos if (!qflag)
2249aa2a9c3Schristos printf("# file: %s\n# owner: %s\n# group: %s\n", path,
2259aa2a9c3Schristos getuname(sb.st_uid), getgname(sb.st_gid));
2269aa2a9c3Schristos
2279aa2a9c3Schristos if (hflag)
2289aa2a9c3Schristos acl = acl_get_link_np(path, type);
2299aa2a9c3Schristos else
2309aa2a9c3Schristos acl = acl_get_file(path, type);
2319aa2a9c3Schristos if (!acl) {
2329aa2a9c3Schristos if (errno != EOPNOTSUPP) {
2339aa2a9c3Schristos warn("%s", path);
2349aa2a9c3Schristos return(-1);
2359aa2a9c3Schristos }
2369aa2a9c3Schristos errno = 0;
2379aa2a9c3Schristos if (type == ACL_TYPE_DEFAULT)
2389aa2a9c3Schristos return(0);
2399aa2a9c3Schristos acl = acl_from_stat(&sb);
2409aa2a9c3Schristos if (!acl) {
2419aa2a9c3Schristos warn("%s: acl_from_stat() failed", path);
2429aa2a9c3Schristos return(-1);
2439aa2a9c3Schristos }
2449aa2a9c3Schristos }
2459aa2a9c3Schristos
2469aa2a9c3Schristos if (iflag)
2479aa2a9c3Schristos flags |= ACL_TEXT_APPEND_ID;
2489aa2a9c3Schristos
2499aa2a9c3Schristos if (nflag)
2509aa2a9c3Schristos flags |= ACL_TEXT_NUMERIC_IDS;
2519aa2a9c3Schristos
2529aa2a9c3Schristos if (vflag)
2539aa2a9c3Schristos flags |= ACL_TEXT_VERBOSE;
2549aa2a9c3Schristos
2559aa2a9c3Schristos acl_text = acl_to_text_np(acl, 0, flags);
2569aa2a9c3Schristos if (!acl_text) {
2579aa2a9c3Schristos warn("%s: acl_to_text_np() failed", path);
2589aa2a9c3Schristos return(-1);
2599aa2a9c3Schristos }
2609aa2a9c3Schristos
2619aa2a9c3Schristos printf("%s", acl_text);
2629aa2a9c3Schristos
2639aa2a9c3Schristos (void)acl_free(acl);
2649aa2a9c3Schristos (void)acl_free(acl_text);
2659aa2a9c3Schristos
2669aa2a9c3Schristos return(0);
2679aa2a9c3Schristos }
2689aa2a9c3Schristos
2699aa2a9c3Schristos static int
print_acl_from_stdin(acl_type_t type,int hflag,int iflag,int nflag,int qflag,int vflag)2709aa2a9c3Schristos print_acl_from_stdin(acl_type_t type, int hflag, int iflag, int nflag,
2719aa2a9c3Schristos int qflag, int vflag)
2729aa2a9c3Schristos {
2739aa2a9c3Schristos char *p, pathname[PATH_MAX];
2749aa2a9c3Schristos int carried_error = 0;
2759aa2a9c3Schristos
2769aa2a9c3Schristos while (fgets(pathname, (int)sizeof(pathname), stdin)) {
2779aa2a9c3Schristos if ((p = strchr(pathname, '\n')) != NULL)
2789aa2a9c3Schristos *p = '\0';
2799aa2a9c3Schristos if (print_acl(pathname, type, hflag, iflag, nflag,
2809aa2a9c3Schristos qflag, vflag) == -1) {
2819aa2a9c3Schristos carried_error = -1;
2829aa2a9c3Schristos }
2839aa2a9c3Schristos }
2849aa2a9c3Schristos
2859aa2a9c3Schristos return(carried_error);
2869aa2a9c3Schristos }
2879aa2a9c3Schristos
2889aa2a9c3Schristos int
main(int argc,char * argv[])2899aa2a9c3Schristos main(int argc, char *argv[])
2909aa2a9c3Schristos {
2919aa2a9c3Schristos acl_type_t type = ACL_TYPE_ACCESS;
2929aa2a9c3Schristos int carried_error = 0;
2939aa2a9c3Schristos int ch, error, i;
2949aa2a9c3Schristos int hflag, iflag, qflag, nflag, vflag;
2959aa2a9c3Schristos
2969aa2a9c3Schristos hflag = 0;
2979aa2a9c3Schristos iflag = 0;
2989aa2a9c3Schristos qflag = 0;
2999aa2a9c3Schristos nflag = 0;
3009aa2a9c3Schristos vflag = 0;
3019aa2a9c3Schristos while ((ch = getopt(argc, argv, "dhinqv")) != -1)
3029aa2a9c3Schristos switch(ch) {
3039aa2a9c3Schristos case 'd':
3049aa2a9c3Schristos type = ACL_TYPE_DEFAULT;
3059aa2a9c3Schristos break;
3069aa2a9c3Schristos case 'h':
3079aa2a9c3Schristos hflag = 1;
3089aa2a9c3Schristos break;
3099aa2a9c3Schristos case 'i':
3109aa2a9c3Schristos iflag = 1;
3119aa2a9c3Schristos break;
3129aa2a9c3Schristos case 'n':
3139aa2a9c3Schristos nflag = 1;
3149aa2a9c3Schristos break;
3159aa2a9c3Schristos case 'q':
3169aa2a9c3Schristos qflag = 1;
3179aa2a9c3Schristos break;
3189aa2a9c3Schristos case 'v':
3199aa2a9c3Schristos vflag = 1;
3209aa2a9c3Schristos break;
3219aa2a9c3Schristos default:
3229aa2a9c3Schristos usage();
3239aa2a9c3Schristos }
3249aa2a9c3Schristos argc -= optind;
3259aa2a9c3Schristos argv += optind;
3269aa2a9c3Schristos
3279aa2a9c3Schristos if (argc == 0) {
3289aa2a9c3Schristos error = print_acl_from_stdin(type, hflag, iflag, nflag,
3299aa2a9c3Schristos qflag, vflag);
3309aa2a9c3Schristos return(error ? 1 : 0);
3319aa2a9c3Schristos }
3329aa2a9c3Schristos
3339aa2a9c3Schristos for (i = 0; i < argc; i++) {
3349aa2a9c3Schristos if (!strcmp(argv[i], "-")) {
3359aa2a9c3Schristos error = print_acl_from_stdin(type, hflag, iflag, nflag,
3369aa2a9c3Schristos qflag, vflag);
3379aa2a9c3Schristos if (error == -1)
3389aa2a9c3Schristos carried_error = -1;
3399aa2a9c3Schristos } else {
3409aa2a9c3Schristos error = print_acl(argv[i], type, hflag, iflag, nflag,
3419aa2a9c3Schristos qflag, vflag);
3429aa2a9c3Schristos if (error == -1)
3439aa2a9c3Schristos carried_error = -1;
3449aa2a9c3Schristos }
3459aa2a9c3Schristos }
3469aa2a9c3Schristos
3479aa2a9c3Schristos return(carried_error ? 1 : 0);
3489aa2a9c3Schristos }
349