1/* $NetBSD: getfacl.c,v 1.2 2020/05/22 01:28:00 joerg Exp $ */ 2 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 36#include <sys/cdefs.h> 37#if 0 38__FBSDID("$FreeBSD: head/bin/getfacl/getfacl.c 340014 2018-11-01 17:45:29Z markj $"); 39#else 40__RCSID("$NetBSD: getfacl.c,v 1.2 2020/05/22 01:28:00 joerg Exp $"); 41#endif 42 43#include <sys/types.h> 44#include <sys/param.h> 45#include <sys/acl.h> 46#include <sys/stat.h> 47 48#include <err.h> 49#include <errno.h> 50#include <grp.h> 51#include <pwd.h> 52#include <stdio.h> 53#include <stdlib.h> 54#include <string.h> 55#include <unistd.h> 56 57static int more_than_one = 0; 58 59static __dead void 60usage(void) 61{ 62 63 fprintf(stderr, "Usage: %s [-dhnqv] [file ...]\n", getprogname()); 64 exit(1); 65} 66 67static char * 68getuname(uid_t uid) 69{ 70 struct passwd *pw; 71 static char uids[10]; 72 73 if ((pw = getpwuid(uid)) == NULL) { 74 (void)snprintf(uids, sizeof(uids), "%u", uid); 75 return (uids); 76 } else 77 return (pw->pw_name); 78} 79 80static char * 81getgname(gid_t gid) 82{ 83 struct group *gr; 84 static char gids[10]; 85 86 if ((gr = getgrgid(gid)) == NULL) { 87 (void)snprintf(gids, sizeof(gids), "%u", gid); 88 return (gids); 89 } else 90 return (gr->gr_name); 91} 92 93/* 94 * return an ACL corresponding to the permissions 95 * contained in struct stat 96 */ 97static acl_t 98acl_from_stat(const struct stat *sb) 99{ 100 acl_t acl; 101 acl_entry_t entry; 102 acl_permset_t perms; 103 104 /* create the ACL */ 105 acl = acl_init(3); 106 if (!acl) 107 return NULL; 108 109 /* First entry: ACL_USER_OBJ */ 110 if (acl_create_entry(&acl, &entry) == -1) 111 return NULL; 112 if (acl_set_tag_type(entry, ACL_USER_OBJ) == -1) 113 return NULL; 114 115 if (acl_get_permset(entry, &perms) == -1) 116 return NULL; 117 if (acl_clear_perms(perms) == -1) 118 return NULL; 119 120 /* calculate user mode */ 121 if (sb->st_mode & S_IRUSR) 122 if (acl_add_perm(perms, ACL_READ) == -1) 123 return NULL; 124 if (sb->st_mode & S_IWUSR) 125 if (acl_add_perm(perms, ACL_WRITE) == -1) 126 return NULL; 127 if (sb->st_mode & S_IXUSR) 128 if (acl_add_perm(perms, ACL_EXECUTE) == -1) 129 return NULL; 130 if (acl_set_permset(entry, perms) == -1) 131 return NULL; 132 133 /* Second entry: ACL_GROUP_OBJ */ 134 if (acl_create_entry(&acl, &entry) == -1) 135 return NULL; 136 if (acl_set_tag_type(entry, ACL_GROUP_OBJ) == -1) 137 return NULL; 138 139 if (acl_get_permset(entry, &perms) == -1) 140 return NULL; 141 if (acl_clear_perms(perms) == -1) 142 return NULL; 143 144 /* calculate group mode */ 145 if (sb->st_mode & S_IRGRP) 146 if (acl_add_perm(perms, ACL_READ) == -1) 147 return NULL; 148 if (sb->st_mode & S_IWGRP) 149 if (acl_add_perm(perms, ACL_WRITE) == -1) 150 return NULL; 151 if (sb->st_mode & S_IXGRP) 152 if (acl_add_perm(perms, ACL_EXECUTE) == -1) 153 return NULL; 154 if (acl_set_permset(entry, perms) == -1) 155 return NULL; 156 157 /* Third entry: ACL_OTHER */ 158 if (acl_create_entry(&acl, &entry) == -1) 159 return NULL; 160 if (acl_set_tag_type(entry, ACL_OTHER) == -1) 161 return NULL; 162 163 if (acl_get_permset(entry, &perms) == -1) 164 return NULL; 165 if (acl_clear_perms(perms) == -1) 166 return NULL; 167 168 /* calculate other mode */ 169 if (sb->st_mode & S_IROTH) 170 if (acl_add_perm(perms, ACL_READ) == -1) 171 return NULL; 172 if (sb->st_mode & S_IWOTH) 173 if (acl_add_perm(perms, ACL_WRITE) == -1) 174 return NULL; 175 if (sb->st_mode & S_IXOTH) 176 if (acl_add_perm(perms, ACL_EXECUTE) == -1) 177 return NULL; 178 if (acl_set_permset(entry, perms) == -1) 179 return NULL; 180 181 return(acl); 182} 183 184static int 185print_acl(char *path, acl_type_t type, int hflag, int iflag, int nflag, 186 int qflag, int vflag) 187{ 188 struct stat sb; 189 acl_t acl; 190 char *acl_text; 191 int error, flags = 0, ret; 192 193 if (hflag) 194 error = lstat(path, &sb); 195 else 196 error = stat(path, &sb); 197 if (error == -1) { 198 warn("%s: stat() failed", path); 199 return(-1); 200 } 201 202 if (hflag) 203 ret = lpathconf(path, _PC_ACL_NFS4); 204 else 205 ret = pathconf(path, _PC_ACL_NFS4); 206 if (ret > 0) { 207 if (type == ACL_TYPE_DEFAULT) { 208 warnx("%s: there are no default entries in NFSv4 ACLs", 209 path); 210 return (-1); 211 } 212 type = ACL_TYPE_NFS4; 213 } else if (ret < 0 && errno != EINVAL) { 214 warn("%s: pathconf(..., _PC_ACL_NFS4) failed", path); 215 return (-1); 216 } 217 218 if (more_than_one) 219 printf("\n"); 220 else 221 more_than_one++; 222 223 if (!qflag) 224 printf("# file: %s\n# owner: %s\n# group: %s\n", path, 225 getuname(sb.st_uid), getgname(sb.st_gid)); 226 227 if (hflag) 228 acl = acl_get_link_np(path, type); 229 else 230 acl = acl_get_file(path, type); 231 if (!acl) { 232 if (errno != EOPNOTSUPP) { 233 warn("%s", path); 234 return(-1); 235 } 236 errno = 0; 237 if (type == ACL_TYPE_DEFAULT) 238 return(0); 239 acl = acl_from_stat(&sb); 240 if (!acl) { 241 warn("%s: acl_from_stat() failed", path); 242 return(-1); 243 } 244 } 245 246 if (iflag) 247 flags |= ACL_TEXT_APPEND_ID; 248 249 if (nflag) 250 flags |= ACL_TEXT_NUMERIC_IDS; 251 252 if (vflag) 253 flags |= ACL_TEXT_VERBOSE; 254 255 acl_text = acl_to_text_np(acl, 0, flags); 256 if (!acl_text) { 257 warn("%s: acl_to_text_np() failed", path); 258 return(-1); 259 } 260 261 printf("%s", acl_text); 262 263 (void)acl_free(acl); 264 (void)acl_free(acl_text); 265 266 return(0); 267} 268 269static int 270print_acl_from_stdin(acl_type_t type, int hflag, int iflag, int nflag, 271 int qflag, int vflag) 272{ 273 char *p, pathname[PATH_MAX]; 274 int carried_error = 0; 275 276 while (fgets(pathname, (int)sizeof(pathname), stdin)) { 277 if ((p = strchr(pathname, '\n')) != NULL) 278 *p = '\0'; 279 if (print_acl(pathname, type, hflag, iflag, nflag, 280 qflag, vflag) == -1) { 281 carried_error = -1; 282 } 283 } 284 285 return(carried_error); 286} 287 288int 289main(int argc, char *argv[]) 290{ 291 acl_type_t type = ACL_TYPE_ACCESS; 292 int carried_error = 0; 293 int ch, error, i; 294 int hflag, iflag, qflag, nflag, vflag; 295 296 hflag = 0; 297 iflag = 0; 298 qflag = 0; 299 nflag = 0; 300 vflag = 0; 301 while ((ch = getopt(argc, argv, "dhinqv")) != -1) 302 switch(ch) { 303 case 'd': 304 type = ACL_TYPE_DEFAULT; 305 break; 306 case 'h': 307 hflag = 1; 308 break; 309 case 'i': 310 iflag = 1; 311 break; 312 case 'n': 313 nflag = 1; 314 break; 315 case 'q': 316 qflag = 1; 317 break; 318 case 'v': 319 vflag = 1; 320 break; 321 default: 322 usage(); 323 } 324 argc -= optind; 325 argv += optind; 326 327 if (argc == 0) { 328 error = print_acl_from_stdin(type, hflag, iflag, nflag, 329 qflag, vflag); 330 return(error ? 1 : 0); 331 } 332 333 for (i = 0; i < argc; i++) { 334 if (!strcmp(argv[i], "-")) { 335 error = print_acl_from_stdin(type, hflag, iflag, nflag, 336 qflag, vflag); 337 if (error == -1) 338 carried_error = -1; 339 } else { 340 error = print_acl(argv[i], type, hflag, iflag, nflag, 341 qflag, vflag); 342 if (error == -1) 343 carried_error = -1; 344 } 345 } 346 347 return(carried_error ? 1 : 0); 348} 349