Print this page
12288 getfacl and setfacl could stand improvement


   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 (c) 1993, 2010, Oracle and/or its affiliates. All rights reserved.

  23  */
  24 
  25 /*
  26  * setfacl [-r] -f aclfile file ...
  27  * setfacl [-r] -d acl_entries file ...
  28  * setfacl [-r] -m acl_entries file ...
  29  * setfacl [-r] -s acl_entries file ...
  30  * This command deletes/adds/modifies/sets discretionary information for a file
  31  * or files.
  32  */
  33 
  34 #include <stdlib.h>
  35 #include <stdio.h>
  36 #include <pwd.h>
  37 #include <grp.h>
  38 #include <string.h>
  39 #include <locale.h>
  40 #include <sys/acl.h>
  41 #include <sys/types.h>
  42 #include <unistd.h>
  43 #include <errno.h>

  44 
  45 #define ADD     1
  46 #define MODIFY  2
  47 #define DELETE  3
  48 #define SET     4
  49 
  50 static int get_acl_info(char *filep, aclent_t **aclpp);
  51 static int mod_entries(aclent_t *, int, char *, char *, char *, int);
  52 static int set_file_entries(char *, char *, int);
  53 static int set_online_entries(char *, char *, int);
  54 static void usage();
  55 static int parse_entry_list(aclent_t **, int *, char *, int);
  56 static int convert_to_aclent_t(char *, int *, aclent_t **, int);
  57 static int parse_entry(char *, aclent_t *, int);
  58 static void err_handle(int, aclent_t *);
  59 static int conv_id(char *);
  60 
  61 int
  62 main(int argc, char *argv[])
  63 {
  64         int             c;
  65         int             dflag = 0;
  66         int             mflag = 0;
  67         int             rflag = 0;
  68         int             sflag = 0;
  69         int             fflag = 0;
  70         int             errflag = 0;
  71         int             aclcnt;                 /* used by -m -d */
  72         aclent_t        *aclp;                  /* used by -m -d */
  73         char            *aclfilep;              /* acl file argument */
  74         char            *d_entryp = NULL;       /* ptr to del entry list */
  75         char            *m_entryp = NULL;       /* ptr to mod entry list */
  76         char            *s_entryp = NULL;       /* ptr to set entry list */
  77         char            *work_dp = NULL;        /* working ptrs for the above */
  78         char            *work_mp = NULL;
  79         char            *work_sp = NULL;
  80 
  81         (void) setlocale(LC_ALL, "");
  82         (void) textdomain(TEXT_DOMAIN);
  83 
  84         if (argc < 3)
  85                 usage();
  86 
  87         while ((c = getopt(argc, argv, "rm:d:s:f:")) != EOF) {
  88                 switch (c) {
  89                 case 'r':
  90                         rflag++;
  91                         break;
  92                 case 'd':
  93                         if (dflag || fflag || sflag)


 182                                 exit(2);
 183                 }
 184         }
 185         return (0);
 186 }
 187 
 188 /*
 189  * For add, modify, and delete, we need to get the ACL of the file first.
 190  */
 191 static int
 192 get_acl_info(char *filep, aclent_t **aclpp)
 193 {
 194         int     aclcnt;
 195 
 196         if ((aclcnt = acl(filep, GETACLCNT, 0, NULL)) < 0) {
 197                 if (errno == ENOSYS) {
 198                         (void) fprintf(stderr,
 199                             gettext("File system doesn't support aclent_t "
 200                             "style ACL's.\n"
 201                             "See acl(5) for more information on"
 202                             " ACL styles support by Solaris.\n"));
 203                         return (-1);
 204                 }
 205                 (void) fprintf(stderr,
 206                     gettext("%s: failed to get acl count\n"), filep);
 207                 perror("get acl count error");
 208                 return (-1);
 209         }
 210         if (aclcnt < MIN_ACL_ENTRIES) {
 211                 (void) fprintf(stderr,
 212                     gettext("%d: acl count is too small from %s\n"),
 213                     aclcnt, filep);
 214                 return (-1);
 215         }
 216 
 217         if ((*aclpp = (aclent_t *)malloc(sizeof (aclent_t) * aclcnt)) == NULL) {
 218                 (void) fprintf(stderr, gettext("out of memory\n"));
 219                 return (-1);
 220         }
 221         if (acl(filep, GETACL, aclcnt, *aclpp) < 0) {
 222                 (void) fprintf(stderr,
 223                     gettext("%s: failed to get acl entries\n"), filep);
 224                 perror("getacl error");
 225                 return (-1);
 226         }
 227         return (aclcnt);
 228 }
 229 
 230 /*
 231  * mod_entries() handles add, delete, and modify ACL entries of a file.
 232  * The real action is in convert_to_aclent_t() called by parse_entry_list().
 233  * aclp: points ACL of a file and may be changed by lower level routine.
 234  * modp: modify entry list in ascii format
 235  * delp: delete entry list in ascii format
 236  * fnamep: file of interest
 237  */
 238 static int
 239 mod_entries(aclent_t *aclp, int cnt, char *modp, char *delp,
 240         char *fnamep, int rfg)
 241 {
 242         int     rc;             /* return code */
 243 
 244         /* modify and add: from -m option */
 245         if (parse_entry_list(&aclp, &cnt, modp, MODIFY) == -1)
 246                 return (-1);
 247 
 248         /* deletion: from -d option */
 249         if (parse_entry_list(&aclp, &cnt, delp, DELETE) == -1)
 250                 return (-1);
 251 
 252         if (aclsort(cnt, rfg, aclp) == -1) {
 253                 (void) err_handle(cnt, aclp);
 254                 (void) fprintf(stderr,
 255                     gettext("aclcnt %d, file %s\n"), cnt, fnamep);
 256                 return (-1);
 257         }
 258 
 259         if (acl(fnamep, SETACL, cnt, aclp) < 0) {
 260                 fprintf(stderr,
 261                     gettext("%s: failed to set acl entries\n"), fnamep);
 262                 perror("setacl error");
 263                 return (-1);


 325         }
 326 
 327         if (acl(fnamep, SETACL, aclcnt, aclp) < 0) {
 328                 fprintf(stderr,
 329                     gettext("%s: failed to set acl entries\n"), fnamep);
 330                 perror("setacl error");
 331                 return (-1);
 332         }
 333         return (0);
 334 }
 335 
 336 /*
 337  * set_online_entries() parses the acl entries from command line (setp).
 338  * It converts the comma separated acl entries into aclent_t format.
 339  * It then recalculates the mask according to rflag.
 340  * Finally it sets ACL to the file (fnamep).
 341  */
 342 static int
 343 set_online_entries(char *setp, char *fnamep, int rflag)
 344 {
 345         char            *commap;
 346         aclent_t        *aclp;
 347         int             aclcnt = 0;
 348 
 349         if (parse_entry_list(&aclp, &aclcnt, setp, SET) == -1)
 350                 return (-1);
 351 
 352         if (aclsort(aclcnt, rflag, aclp) == -1) {
 353                 (void) err_handle(aclcnt, aclp);
 354                 (void) fprintf(stderr,
 355                     gettext("aclcnt %d, file %s\n"), aclcnt, fnamep);
 356                 return (-1);
 357         }
 358 
 359         if (acl(fnamep, SETACL, aclcnt, aclp) < 0) {
 360                 fprintf(stderr,
 361                     gettext("%s: failed to set acl entries\n"), fnamep);
 362                 perror("setacl error");
 363                 return (-1);
 364         }
 365         return (0);


 397 /*
 398  * convert_to_aclent_t() converts an acl entry in ascii format (fields separated
 399  * by colon) into aclent_t and appends it to the current ACL. It also handles
 400  * memory allocation/deallocation for acl entries in aclent_t format.
 401  * aclpp that contains acl entries in acl format will be returned.
 402  * We don't check duplicates.
 403  */
 404 static int
 405 convert_to_aclent_t(char *entryp, int *cntp, aclent_t **aclpp, int mode)
 406 {
 407         aclent_t        *new_aclp;
 408         aclent_t        tmpacl;
 409         aclent_t        *taclp, *centry = NULL, *gentry = NULL;
 410         int             cur_cnt;
 411         int             found = 0;
 412         int             is_obj;
 413 
 414         if (entryp == NULL)
 415                 return (0);
 416 
 417         if (*cntp > 1)
 418                 new_aclp = (aclent_t *)realloc(*aclpp,
 419                     sizeof (aclent_t) * (*cntp));
 420         else
 421                 new_aclp = (aclent_t *) malloc(sizeof (aclent_t) * (*cntp));
 422         if (new_aclp == NULL) {
 423                 fprintf(stderr,
 424                     gettext("Insufficient memory for acl %d\n"), *cntp);
 425                 return (-1);
 426         }
 427 
 428         tmpacl.a_id = 0;        /* id field needs to be initialized */
 429         if (entryp[0] == 'u')
 430                 tmpacl.a_id = getuid(); /* id field for user */
 431         if (entryp[0] == 'g')
 432                 tmpacl.a_id = getgid(); /* id field for group */
 433 
 434         tmpacl.a_type = 0;
 435         if (parse_entry(entryp, &tmpacl, mode) == -1)
 436                 return (-1);
 437 
 438         is_obj = ((tmpacl.a_type == USER_OBJ) ||
 439             (tmpacl.a_type == GROUP_OBJ) ||
 440             (tmpacl.a_type == CLASS_OBJ) ||
 441             (tmpacl.a_type == DEF_USER_OBJ) ||
 442             (tmpacl.a_type == DEF_GROUP_OBJ) ||
 443             (tmpacl.a_type == DEF_OTHER_OBJ));
 444 











 445         cur_cnt = *cntp - 1;
 446         switch (mode) {
 447         case MODIFY:    /* and add */
 448                 for (taclp = new_aclp; cur_cnt-- > 0; taclp++) {
 449                         if (taclp->a_type == tmpacl.a_type &&
 450                             ((taclp->a_id == tmpacl.a_id) || is_obj)) {
 451                                 found++;
 452                                 /* cnt is added before it's called */
 453                                 *cntp -= 1;
 454                                 taclp->a_perm = tmpacl.a_perm;
 455                                 break;
 456                         }
 457                 }
 458                 if (!found)     /* Add it to the end: no need to change cntp */
 459                         memcpy(new_aclp + *cntp -1, &tmpacl, sizeof (aclent_t));
 460                 break;
 461 
 462         case DELETE:
 463                 for (taclp = new_aclp; cur_cnt-- > 0; taclp++) {
 464                         if (taclp->a_type == tmpacl.a_type &&




   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 (c) 1993, 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright 2020 Peter Tribble.
  24  */
  25 
  26 /*
  27  * setfacl [-r] -f aclfile file ...
  28  * setfacl [-r] -d acl_entries file ...
  29  * setfacl [-r] -m acl_entries file ...
  30  * setfacl [-r] -s acl_entries file ...
  31  * This command deletes/adds/modifies/sets discretionary information for a file
  32  * or files.
  33  */
  34 
  35 #include <stdlib.h>
  36 #include <stdio.h>
  37 #include <pwd.h>
  38 #include <grp.h>
  39 #include <string.h>
  40 #include <locale.h>
  41 #include <sys/acl.h>
  42 #include <sys/types.h>
  43 #include <unistd.h>
  44 #include <errno.h>
  45 #include <ctype.h>
  46 
  47 #define ADD     1
  48 #define MODIFY  2
  49 #define DELETE  3
  50 #define SET     4
  51 
  52 static int get_acl_info(char *filep, aclent_t **aclpp);
  53 static int mod_entries(aclent_t *, int, char *, char *, char *, int);
  54 static int set_file_entries(char *, char *, int);
  55 static int set_online_entries(char *, char *, int);
  56 static void usage();
  57 static int parse_entry_list(aclent_t **, int *, char *, int);
  58 static int convert_to_aclent_t(char *, int *, aclent_t **, int);
  59 static int parse_entry(char *, aclent_t *, int);
  60 static void err_handle(int, aclent_t *);
  61 static int conv_id(char *);
  62 
  63 int
  64 main(int argc, char *argv[])
  65 {
  66         int             c;
  67         int             dflag = 0;
  68         int             mflag = 0;
  69         int             rflag = 0;
  70         int             sflag = 0;
  71         int             fflag = 0;
  72         int             errflag = 0;
  73         int             aclcnt;                 /* used by -m -d */
  74         aclent_t        *aclp;                  /* used by -m -d */
  75         char            *aclfilep = NULL;               /* acl file argument */
  76         char            *d_entryp = NULL;       /* ptr to del entry list */
  77         char            *m_entryp = NULL;       /* ptr to mod entry list */
  78         char            *s_entryp = NULL;       /* ptr to set entry list */
  79         char            *work_dp = NULL;        /* working ptrs for the above */
  80         char            *work_mp = NULL;
  81         char            *work_sp = NULL;
  82 
  83         (void) setlocale(LC_ALL, "");
  84         (void) textdomain(TEXT_DOMAIN);
  85 
  86         if (argc < 3)
  87                 usage();
  88 
  89         while ((c = getopt(argc, argv, "rm:d:s:f:")) != EOF) {
  90                 switch (c) {
  91                 case 'r':
  92                         rflag++;
  93                         break;
  94                 case 'd':
  95                         if (dflag || fflag || sflag)


 184                                 exit(2);
 185                 }
 186         }
 187         return (0);
 188 }
 189 
 190 /*
 191  * For add, modify, and delete, we need to get the ACL of the file first.
 192  */
 193 static int
 194 get_acl_info(char *filep, aclent_t **aclpp)
 195 {
 196         int     aclcnt;
 197 
 198         if ((aclcnt = acl(filep, GETACLCNT, 0, NULL)) < 0) {
 199                 if (errno == ENOSYS) {
 200                         (void) fprintf(stderr,
 201                             gettext("File system doesn't support aclent_t "
 202                             "style ACL's.\n"
 203                             "See acl(5) for more information on"
 204                             "POSIX-draft ACL support.\n"));
 205                         return (-1);
 206                 }
 207                 (void) fprintf(stderr,
 208                     gettext("%s: failed to get acl count\n"), filep);
 209                 perror("get acl count error");
 210                 return (-1);
 211         }
 212         if (aclcnt < MIN_ACL_ENTRIES) {
 213                 (void) fprintf(stderr,
 214                     gettext("%d: acl count is too small from %s\n"),
 215                     aclcnt, filep);
 216                 return (-1);
 217         }
 218 
 219         if ((*aclpp = (aclent_t *)malloc(sizeof (aclent_t) * aclcnt)) == NULL) {
 220                 (void) fprintf(stderr, gettext("out of memory\n"));
 221                 return (-1);
 222         }
 223         if (acl(filep, GETACL, aclcnt, *aclpp) < 0) {
 224                 (void) fprintf(stderr,
 225                     gettext("%s: failed to get acl entries\n"), filep);
 226                 perror("getacl error");
 227                 return (-1);
 228         }
 229         return (aclcnt);
 230 }
 231 
 232 /*
 233  * mod_entries() handles add, delete, and modify ACL entries of a file.
 234  * The real action is in convert_to_aclent_t() called by parse_entry_list().
 235  * aclp: points ACL of a file and may be changed by lower level routine.
 236  * modp: modify entry list in ascii format
 237  * delp: delete entry list in ascii format
 238  * fnamep: file of interest
 239  */
 240 static int
 241 mod_entries(aclent_t *aclp, int cnt, char *modp, char *delp,
 242     char *fnamep, int rfg)
 243 {


 244         /* modify and add: from -m option */
 245         if (parse_entry_list(&aclp, &cnt, modp, MODIFY) == -1)
 246                 return (-1);
 247 
 248         /* deletion: from -d option */
 249         if (parse_entry_list(&aclp, &cnt, delp, DELETE) == -1)
 250                 return (-1);
 251 
 252         if (aclsort(cnt, rfg, aclp) == -1) {
 253                 (void) err_handle(cnt, aclp);
 254                 (void) fprintf(stderr,
 255                     gettext("aclcnt %d, file %s\n"), cnt, fnamep);
 256                 return (-1);
 257         }
 258 
 259         if (acl(fnamep, SETACL, cnt, aclp) < 0) {
 260                 fprintf(stderr,
 261                     gettext("%s: failed to set acl entries\n"), fnamep);
 262                 perror("setacl error");
 263                 return (-1);


 325         }
 326 
 327         if (acl(fnamep, SETACL, aclcnt, aclp) < 0) {
 328                 fprintf(stderr,
 329                     gettext("%s: failed to set acl entries\n"), fnamep);
 330                 perror("setacl error");
 331                 return (-1);
 332         }
 333         return (0);
 334 }
 335 
 336 /*
 337  * set_online_entries() parses the acl entries from command line (setp).
 338  * It converts the comma separated acl entries into aclent_t format.
 339  * It then recalculates the mask according to rflag.
 340  * Finally it sets ACL to the file (fnamep).
 341  */
 342 static int
 343 set_online_entries(char *setp, char *fnamep, int rflag)
 344 {

 345         aclent_t        *aclp;
 346         int             aclcnt = 0;
 347 
 348         if (parse_entry_list(&aclp, &aclcnt, setp, SET) == -1)
 349                 return (-1);
 350 
 351         if (aclsort(aclcnt, rflag, aclp) == -1) {
 352                 (void) err_handle(aclcnt, aclp);
 353                 (void) fprintf(stderr,
 354                     gettext("aclcnt %d, file %s\n"), aclcnt, fnamep);
 355                 return (-1);
 356         }
 357 
 358         if (acl(fnamep, SETACL, aclcnt, aclp) < 0) {
 359                 fprintf(stderr,
 360                     gettext("%s: failed to set acl entries\n"), fnamep);
 361                 perror("setacl error");
 362                 return (-1);
 363         }
 364         return (0);


 396 /*
 397  * convert_to_aclent_t() converts an acl entry in ascii format (fields separated
 398  * by colon) into aclent_t and appends it to the current ACL. It also handles
 399  * memory allocation/deallocation for acl entries in aclent_t format.
 400  * aclpp that contains acl entries in acl format will be returned.
 401  * We don't check duplicates.
 402  */
 403 static int
 404 convert_to_aclent_t(char *entryp, int *cntp, aclent_t **aclpp, int mode)
 405 {
 406         aclent_t        *new_aclp;
 407         aclent_t        tmpacl;
 408         aclent_t        *taclp, *centry = NULL, *gentry = NULL;
 409         int             cur_cnt;
 410         int             found = 0;
 411         int             is_obj;
 412 
 413         if (entryp == NULL)
 414                 return (0);
 415 











 416         tmpacl.a_id = 0;        /* id field needs to be initialized */
 417         if (entryp[0] == 'u')
 418                 tmpacl.a_id = getuid(); /* id field for user */
 419         if (entryp[0] == 'g')
 420                 tmpacl.a_id = getgid(); /* id field for group */
 421 
 422         tmpacl.a_type = 0;
 423         if (parse_entry(entryp, &tmpacl, mode) == -1)
 424                 return (-1);
 425 
 426         is_obj = ((tmpacl.a_type == USER_OBJ) ||
 427             (tmpacl.a_type == GROUP_OBJ) ||
 428             (tmpacl.a_type == CLASS_OBJ) ||
 429             (tmpacl.a_type == DEF_USER_OBJ) ||
 430             (tmpacl.a_type == DEF_GROUP_OBJ) ||
 431             (tmpacl.a_type == DEF_OTHER_OBJ));
 432 
 433         if (*cntp > 1)
 434                 new_aclp = (aclent_t *)realloc(*aclpp,
 435                     sizeof (aclent_t) * (*cntp));
 436         else
 437                 new_aclp = (aclent_t *) malloc(sizeof (aclent_t) * (*cntp));
 438         if (new_aclp == NULL) {
 439                 fprintf(stderr,
 440                     gettext("Insufficient memory for acl %d\n"), *cntp);
 441                 return (-1);
 442         }
 443 
 444         cur_cnt = *cntp - 1;
 445         switch (mode) {
 446         case MODIFY:    /* and add */
 447                 for (taclp = new_aclp; cur_cnt-- > 0; taclp++) {
 448                         if (taclp->a_type == tmpacl.a_type &&
 449                             ((taclp->a_id == tmpacl.a_id) || is_obj)) {
 450                                 found++;
 451                                 /* cnt is added before it's called */
 452                                 *cntp -= 1;
 453                                 taclp->a_perm = tmpacl.a_perm;
 454                                 break;
 455                         }
 456                 }
 457                 if (!found)     /* Add it to the end: no need to change cntp */
 458                         memcpy(new_aclp + *cntp -1, &tmpacl, sizeof (aclent_t));
 459                 break;
 460 
 461         case DELETE:
 462                 for (taclp = new_aclp; cur_cnt-- > 0; taclp++) {
 463                         if (taclp->a_type == tmpacl.a_type &&