1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  * Copyright 2020 Peter Tribble.
  25  */
  26 
  27 /*
  28  * getfacl [-ad] file ...
  29  * This command displays discretionary information for a file or files.
  30  * display format:
  31  *      # file: filename
  32  *      # owner: uid
  33  *      # group: gid
  34  *      user::perm
  35  *      user:uid:perm
  36  *      group::perm
  37  *      group:gid:perm
  38  *      mask:perm
  39  *      other:perm
  40  *      default:user::perm
  41  *      default:user:uid:perm
  42  *      default:group::perm
  43  *      default:group:gid:perm
  44  *      default:mask:perm
  45  *      default:other:perm
  46  */
  47 
  48 #include <stdlib.h>
  49 #include <stdio.h>
  50 #include <pwd.h>
  51 #include <grp.h>
  52 #include <locale.h>
  53 #include <sys/acl.h>
  54 #include <errno.h>
  55 
  56 static char     *pruname(uid_t);
  57 static char     *prgname(gid_t);
  58 static char     *display(int);
  59 static void     usage();
  60 
  61 
  62 int
  63 main(int argc, char *argv[])
  64 {
  65         int             c;
  66         int             aflag = 0;
  67         int             dflag = 0;
  68         int             errflag = 0;
  69         int             savecnt;
  70         int             aclcnt;
  71         int             mask = 0;
  72         aclent_t        *aclp;
  73         aclent_t        *tp;
  74         char            *permp;
  75 
  76         (void) setlocale(LC_ALL, "");
  77         (void) textdomain(TEXT_DOMAIN);
  78 
  79         if (argc < 2)
  80                 usage();
  81 
  82         while ((c = getopt(argc, argv, "ad")) != EOF) {
  83                 switch (c) {
  84                 case 'a':
  85                         aflag++;
  86                         break;
  87                 case 'd':
  88                         dflag++;
  89                         break;
  90                 case '?':
  91                         errflag++;
  92                         break;
  93                 }
  94         }
  95         if (errflag)
  96                 usage();
  97 
  98         if (optind >= argc)
  99                 usage();
 100 
 101         for (; optind < argc; optind++) {
 102                 register char *filep;
 103 
 104                 filep = argv[optind];
 105 
 106                 /* Get ACL info of the files */
 107                 errno = 0;
 108                 if ((aclcnt = acl(filep, GETACLCNT, 0, NULL)) < 0) {
 109                         if (errno == ENOSYS) {
 110                                 (void) fprintf(stderr,
 111                                     gettext("File system doesn't support "
 112                                     "aclent_t style ACL's.\n"
 113                                     "See acl(5) for more information on "
 114                                     "POSIX-draft ACL support.\n"));
 115                                 exit(2);
 116                         }
 117                         perror(filep);
 118                         exit(2);
 119                 }
 120                 if (aclcnt < MIN_ACL_ENTRIES) {
 121                         (void) fprintf(stderr,
 122                             gettext("%d: acl count too small from %s\n"),
 123                             aclcnt, filep);
 124                         exit(2);
 125                 }
 126 
 127                 if ((aclp = (aclent_t *)malloc(sizeof (aclent_t) * aclcnt))
 128                     == NULL) {
 129                         (void) fprintf(stderr,
 130                             gettext("Insufficient memory\n"));
 131                         exit(1);
 132                 }
 133 
 134                 errno = 0;
 135                 if (acl(filep, GETACL, aclcnt, aclp) < 0) {
 136                         perror(filep);
 137                         exit(2);
 138                 }
 139 
 140                 /* display ACL: assume it is sorted. */
 141                 (void) printf("\n# file: %s\n", filep);
 142                 savecnt = aclcnt;
 143                 for (tp = aclp; aclcnt--; tp++) {
 144                         if (tp->a_type == USER_OBJ)
 145                                 (void) printf("# owner: %s\n",
 146                                     pruname(tp->a_id));
 147                         if (tp->a_type == GROUP_OBJ)
 148                                 (void) printf("# group: %s\n",
 149                                     prgname(tp->a_id));
 150                         if (tp->a_type == CLASS_OBJ)
 151                                 mask = tp->a_perm;
 152                 }
 153                 aclcnt = savecnt;
 154                 for (tp = aclp; aclcnt--; tp++) {
 155                         switch (tp->a_type) {
 156                         case USER:
 157                                 if (!dflag) {
 158                                         permp = display(tp->a_perm);
 159                                         (void) printf("user:%s:%s\t\t",
 160                                             pruname(tp->a_id), permp);
 161                                         free(permp);
 162                                         permp = display(tp->a_perm & mask);
 163                                         (void) printf(
 164                                             "#effective:%s\n", permp);
 165                                         free(permp);
 166                                 }
 167                                 break;
 168                         case USER_OBJ:
 169                                 if (!dflag) {
 170                                         /* no need to display uid */
 171                                         permp = display(tp->a_perm);
 172                                         (void) printf("user::%s\n", permp);
 173                                         free(permp);
 174                                 }
 175                                 break;
 176                         case GROUP:
 177                                 if (!dflag) {
 178                                         permp = display(tp->a_perm);
 179                                         (void) printf("group:%s:%s\t\t",
 180                                             prgname(tp->a_id), permp);
 181                                         free(permp);
 182                                         permp = display(tp->a_perm & mask);
 183                                         (void) printf(
 184                                             "#effective:%s\n", permp);
 185                                         free(permp);
 186                                 }
 187                                 break;
 188                         case GROUP_OBJ:
 189                                 if (!dflag) {
 190                                         permp = display(tp->a_perm);
 191                                         (void) printf("group::%s\t\t", permp);
 192                                         free(permp);
 193                                         permp = display(tp->a_perm & mask);
 194                                         (void) printf(
 195                                             "#effective:%s\n", permp);
 196                                         free(permp);
 197                                 }
 198                                 break;
 199                         case CLASS_OBJ:
 200                                 if (!dflag) {
 201                                         permp = display(tp->a_perm);
 202                                         (void) printf("mask:%s\n", permp);
 203                                         free(permp);
 204                                 }
 205                                 break;
 206                         case OTHER_OBJ:
 207                                 if (!dflag) {
 208                                         permp = display(tp->a_perm);
 209                                         (void) printf("other:%s\n", permp);
 210                                         free(permp);
 211                                 }
 212                                 break;
 213                         case DEF_USER:
 214                                 if (!aflag) {
 215                                         permp = display(tp->a_perm);
 216                                         (void) printf("default:user:%s:%s\n",
 217                                             pruname(tp->a_id), permp);
 218                                         free(permp);
 219                                 }
 220                                 break;
 221                         case DEF_USER_OBJ:
 222                                 if (!aflag) {
 223                                         permp = display(tp->a_perm);
 224                                         (void) printf("default:user::%s\n",
 225                                             permp);
 226                                         free(permp);
 227                                 }
 228                                 break;
 229                         case DEF_GROUP:
 230                                 if (!aflag) {
 231                                         permp = display(tp->a_perm);
 232                                         (void) printf("default:group:%s:%s\n",
 233                                             prgname(tp->a_id), permp);
 234                                         free(permp);
 235                                 }
 236                                 break;
 237                         case DEF_GROUP_OBJ:
 238                                 if (!aflag) {
 239                                         permp = display(tp->a_perm);
 240                                         (void) printf("default:group::%s\n",
 241                                             permp);
 242                                         free(permp);
 243                                 }
 244                                 break;
 245                         case DEF_CLASS_OBJ:
 246                                 if (!aflag) {
 247                                         permp = display(tp->a_perm);
 248                                         (void) printf("default:mask:%s\n",
 249                                             permp);
 250                                         free(permp);
 251                                 }
 252                                 break;
 253                         case DEF_OTHER_OBJ:
 254                                 if (!aflag) {
 255                                         permp = display(tp->a_perm);
 256                                         (void) printf("default:other:%s\n",
 257                                             permp);
 258                                         free(permp);
 259                                 }
 260                                 break;
 261                         default:
 262                                 (void) fprintf(stderr,
 263                                     gettext("unrecognized entry\n"));
 264                                 break;
 265                         }
 266                 }
 267                 free(aclp);
 268         }
 269         return (0);
 270 }
 271 
 272 static char *
 273 display(int perm)
 274 {
 275         char    *buf;
 276 
 277         buf = malloc(4);
 278         if (buf == NULL) {
 279                 (void) fprintf(stderr, gettext("Insufficient memory\n"));
 280                 exit(1);
 281         }
 282 
 283         if (perm & 4)
 284                 buf[0] = 'r';
 285         else
 286                 buf[0] = '-';
 287         if (perm & 2)
 288                 buf[1] = 'w';
 289         else
 290                 buf[1] = '-';
 291         if (perm & 1)
 292                 buf[2] = 'x';
 293         else
 294                 buf[2] = '-';
 295         buf[3] = '\0';
 296         return (buf);
 297 }
 298 
 299 static char *
 300 pruname(uid_t uid)
 301 {
 302         struct passwd   *passwdp;
 303         static char     uidp[10];       /* big enough */
 304 
 305         passwdp = getpwuid(uid);
 306         if (passwdp == (struct passwd *)NULL) {
 307                 /* could not get passwd information: display uid instead */
 308                 (void) sprintf(uidp, "%u", uid);
 309                 return (uidp);
 310         } else
 311                 return (passwdp->pw_name);
 312 }
 313 
 314 static char *
 315 prgname(gid_t gid)
 316 {
 317         struct group    *groupp;
 318         static char     gidp[10];       /* big enough */
 319 
 320         groupp = getgrgid(gid);
 321         if (groupp == (struct group *)NULL) {
 322                 /* could not get group information: display gid instead */
 323                 (void) sprintf(gidp, "%u", gid);
 324                 return (gidp);
 325         } else
 326                 return (groupp->gr_name);
 327 }
 328 
 329 static void
 330 usage()
 331 {
 332         (void) fprintf(stderr,
 333             gettext("usage: getfacl [-ad] file ... \n"));
 334         exit(1);
 335 }