1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 1999, 2001, 2002 Robert N M Watson 5 * All rights reserved. 6 * 7 * This software was developed by Robert Watson for the TrustedBSD Project. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 /* 31 * getfacl -- POSIX.1e utility to extract ACLs from files and directories 32 * and send the results to stdout 33 */ 34 35 #include <sys/types.h> 36 #include <sys/param.h> 37 #include <sys/acl.h> 38 #include <sys/stat.h> 39 40 #include <err.h> 41 #include <errno.h> 42 #include <getopt.h> 43 #include <grp.h> 44 #include <pwd.h> 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <string.h> 48 #include <unistd.h> 49 50 static int more_than_one = 0; 51 52 static const struct option long_options[] = 53 { 54 { "default", no_argument, NULL, 'd' }, 55 { "numeric", no_argument, NULL, 'n' }, 56 { "omit-header", no_argument, NULL, 'q' }, 57 { "skip-base", no_argument, NULL, 's' }, 58 { NULL, no_argument, NULL, 0 }, 59 }; 60 61 static void 62 usage(void) 63 { 64 65 fprintf(stderr, "getfacl [-dhnqv] [file ...]\n"); 66 } 67 68 static char * 69 getuname(uid_t uid) 70 { 71 struct passwd *pw; 72 static char uids[10]; 73 74 if ((pw = getpwuid(uid)) == NULL) { 75 (void)snprintf(uids, sizeof(uids), "%u", uid); 76 return (uids); 77 } else 78 return (pw->pw_name); 79 } 80 81 static char * 82 getgname(gid_t gid) 83 { 84 struct group *gr; 85 static char gids[10]; 86 87 if ((gr = getgrgid(gid)) == NULL) { 88 (void)snprintf(gids, sizeof(gids), "%u", gid); 89 return (gids); 90 } else 91 return (gr->gr_name); 92 } 93 94 static int 95 print_acl(char *path, acl_type_t type, int hflag, int iflag, int nflag, 96 int qflag, int vflag, int sflag) 97 { 98 struct stat sb; 99 acl_t acl; 100 char *acl_text; 101 int error, flags = 0, ret; 102 103 if (hflag) 104 error = lstat(path, &sb); 105 else 106 error = stat(path, &sb); 107 if (error == -1) { 108 warn("%s: stat() failed", path); 109 return(-1); 110 } 111 112 if (hflag) 113 ret = lpathconf(path, _PC_ACL_NFS4); 114 else 115 ret = pathconf(path, _PC_ACL_NFS4); 116 if (ret > 0) { 117 if (type == ACL_TYPE_DEFAULT) { 118 warnx("%s: there are no default entries in NFSv4 ACLs", 119 path); 120 return (-1); 121 } 122 type = ACL_TYPE_NFS4; 123 } else if (ret < 0 && errno != EINVAL) { 124 warn("%s: pathconf(..., _PC_ACL_NFS4) failed", path); 125 return (-1); 126 } 127 128 if (hflag) 129 acl = acl_get_link_np(path, type); 130 else 131 acl = acl_get_file(path, type); 132 133 if (!acl && errno != EOPNOTSUPP) { 134 warn("%s", path); 135 return(-1); 136 } 137 138 if (sflag) { 139 int trivial; 140 141 /* 142 * With the -s flag, we shouldn't synthesize a trivial ACL if 143 * they aren't supported as we do below. 144 */ 145 if (!acl) 146 return(0); 147 148 /* 149 * We also shouldn't render anything for this path if it's a 150 * trivial ACL. If we error out, we'll issue a warning but 151 * proceed with this file to err on the side of caution. 152 */ 153 error = acl_is_trivial_np(acl, &trivial); 154 if (error != 0) { 155 warn("%s: acl_is_trivial_np failed", path); 156 } else if (trivial) { 157 (void)acl_free(acl); 158 return(0); 159 } 160 } 161 162 if (more_than_one) 163 printf("\n"); 164 else 165 more_than_one++; 166 if (!qflag) 167 printf("# file: %s\n# owner: %s\n# group: %s\n", path, 168 getuname(sb.st_uid), getgname(sb.st_gid)); 169 170 if (!acl) { 171 if (type == ACL_TYPE_DEFAULT) 172 return(0); 173 acl = acl_from_mode_np(sb.st_mode); 174 if (!acl) { 175 warn("%s: acl_from_mode() failed", path); 176 return(-1); 177 } 178 } 179 180 if (iflag) 181 flags |= ACL_TEXT_APPEND_ID; 182 183 if (nflag) 184 flags |= ACL_TEXT_NUMERIC_IDS; 185 186 if (vflag) 187 flags |= ACL_TEXT_VERBOSE; 188 189 acl_text = acl_to_text_np(acl, 0, flags); 190 if (!acl_text) { 191 warn("%s: acl_to_text_np() failed", path); 192 (void)acl_free(acl); 193 return(-1); 194 } 195 196 printf("%s", acl_text); 197 198 (void)acl_free(acl); 199 (void)acl_free(acl_text); 200 201 return(0); 202 } 203 204 static int 205 print_acl_from_stdin(acl_type_t type, int hflag, int iflag, int nflag, 206 int qflag, int vflag, int sflag) 207 { 208 char *p, pathname[PATH_MAX]; 209 int carried_error = 0; 210 211 while (fgets(pathname, (int)sizeof(pathname), stdin)) { 212 if ((p = strchr(pathname, '\n')) != NULL) 213 *p = '\0'; 214 if (print_acl(pathname, type, hflag, iflag, nflag, 215 qflag, vflag, sflag) == -1) { 216 carried_error = -1; 217 } 218 } 219 220 return(carried_error); 221 } 222 223 int 224 main(int argc, char *argv[]) 225 { 226 acl_type_t type = ACL_TYPE_ACCESS; 227 int carried_error = 0; 228 int ch, error, i; 229 int hflag, iflag, qflag, nflag, sflag, vflag; 230 231 hflag = 0; 232 iflag = 0; 233 qflag = 0; 234 nflag = 0; 235 sflag = 0; 236 vflag = 0; 237 while ((ch = getopt_long(argc, argv, "+dhinqsv", long_options, 238 NULL)) != -1) 239 switch(ch) { 240 case 'd': 241 type = ACL_TYPE_DEFAULT; 242 break; 243 case 'h': 244 hflag = 1; 245 break; 246 case 'i': 247 iflag = 1; 248 break; 249 case 'n': 250 nflag = 1; 251 break; 252 case 'q': 253 qflag = 1; 254 break; 255 case 's': 256 sflag = 1; 257 break; 258 case 'v': 259 vflag = 1; 260 break; 261 default: 262 usage(); 263 return(-1); 264 } 265 argc -= optind; 266 argv += optind; 267 268 if (argc == 0) { 269 error = print_acl_from_stdin(type, hflag, iflag, nflag, 270 qflag, vflag, sflag); 271 return(error ? 1 : 0); 272 } 273 274 for (i = 0; i < argc; i++) { 275 if (!strcmp(argv[i], "-")) { 276 error = print_acl_from_stdin(type, hflag, iflag, nflag, 277 qflag, vflag, sflag); 278 if (error == -1) 279 carried_error = -1; 280 } else { 281 error = print_acl(argv[i], type, hflag, iflag, nflag, 282 qflag, vflag, sflag); 283 if (error == -1) 284 carried_error = -1; 285 } 286 } 287 288 return(carried_error ? 1 : 0); 289 } 290