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, Version 1.0 only
   6  * (the "License").  You may not use this file except in compliance
   7  * with the License.
   8  *
   9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  10  * or http://www.opensolaris.org/os/licensing.
  11  * See the License for the specific language governing permissions
  12  * and limitations under the License.
  13  *
  14  * When distributing Covered Code, include this CDDL HEADER in each
  15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  16  * If applicable, add the following below this CDDL HEADER, with the
  17  * fields enclosed by brackets "[]" replaced with your own identifying
  18  * information: Portions Copyright [yyyy] [name of copyright owner]
  19  *
  20  * CDDL HEADER END
  21  */
  22 /*
  23  * Copyright (c) 1995 Sun Microsystems, Inc.  All Rights Reserved
  24  *
  25  * module:
  26  *      acls.c
  27  *
  28  * purpose:
  29  *      routines to manipulate access control lists, mapping between
  30  *      the data structures required by the filesystem ACL system calls
  31  *      and the representation used in our fileinfo structure.
  32  *
  33  */
  34 #ident  "%W%    %E% SMI"
  35 
  36 #include <stdio.h>
  37 #include <stdlib.h>
  38 
  39 #include "filesync.h"
  40 #include "database.h"
  41 
  42 #ifdef NO_ACLS
  43 /*
  44  * Solaris 2.4 libc.so does not contain this entry point, so if we
  45  * want to build a 2.4 version of filesync, we need to provide a
  46  * dummy entry point that will fail when-ever it is called.
  47  */
  48 #define acl     bogus_acl
  49 
  50 static int acl(const char *name, int opcode, int count, aclent_t *acls)
  51 {
  52         return (-1);
  53 }
  54 #endif
  55 
  56 /*
  57  * routine:
  58  *      get_acls
  59  *
  60  * purpose:
  61  *      to read the ACL (if any) from a file into a fileinfo structure
  62  *
  63  * parameters:
  64  *      name of file
  65  *      pointer to fileinfo structure
  66  *
  67  * returns:
  68  *      number of ACL entries
  69  */
  70 int
  71 get_acls(const char *name, struct fileinfo *ip)
  72 {       int count;
  73         int i;
  74         static aclent_t acls[MAX_ACL_ENTRIES];
  75         aclent_t *list;
  76 
  77         count = acl(name, GETACL, MAX_ACL_ENTRIES, acls);
  78         if (count <= 0)
  79                 return (0);
  80 
  81         /* with a count of 3 or 4 there may not be any real ones */
  82         if (count > 4)
  83                 goto gotsome;
  84 
  85         /* look for anything beyond the normal unix protection  */
  86         for (i = 0; i < count; i++)
  87                 switch (acls[i].a_type) {
  88                         default:        /* weird types are real */
  89                                 goto gotsome;
  90 
  91                         case USER_OBJ:
  92                         case GROUP_OBJ:
  93                         case OTHER_OBJ:
  94                         case CLASS_OBJ:
  95                                 continue; /* all file have these */
  96                 }
  97 
  98         return (0);     /* nothing interesting  */
  99 
 100 gotsome:
 101         /* allocate an array to hold the acls           */
 102         list = (aclent_t *) malloc(count * sizeof (*list));
 103         if (list == 0)
 104                 nomem("Access Control List");
 105 
 106         /* copy the acls into the new list              */
 107         for (i = 0; i < count; i++) {
 108                 list[i].a_type = acls[i].a_type;
 109                 list[i].a_id = acls[i].a_id;
 110                 list[i].a_perm = acls[i].a_perm;
 111         }
 112 
 113         ip->f_acls = list;
 114         ip->f_numacls = count;
 115         return (ip->f_numacls);
 116 }
 117 
 118 /*
 119  * routine:
 120  *      cmp_acls
 121  *
 122  * purpose:
 123  *      determine whether or not two ACLs are the same
 124  *
 125  * parameters:
 126  *      pointer to first fileinfo
 127  *      pointer to second fileinfo
 128  *
 129  * returns:
 130  *      true    equal
 131  *      false   different
 132  */
 133 int
 134 cmp_acls(struct fileinfo *f1, struct fileinfo *f2)
 135 {       int i;
 136 
 137         if (f1->f_numacls != f2->f_numacls)
 138                 return (0);
 139 
 140         if (f1->f_numacls == 0)
 141                 return (1);
 142 
 143         for (i = 0; i < f1->f_numacls; i++) {
 144                 if (f1->f_acls[i].a_type != f2->f_acls[i].a_type)
 145                         return (0);
 146                 if (f1->f_acls[i].a_id != f2->f_acls[i].a_id)
 147                         return (0);
 148                 if (f1->f_acls[i].a_perm != f2->f_acls[i].a_perm)
 149                         return (0);
 150         }
 151 
 152         return (1);
 153 }
 154 
 155 /*
 156  * routine:
 157  *      set_acls
 158  *
 159  * purpose:
 160  *      to write the ACL of a file
 161  *
 162  * parameters:
 163  *      name of file
 164  *      fileinfo pointer (which contains an acl pointer)
 165  *
 166  * returns:
 167  *      retcode and errno
 168  */
 169 int
 170 set_acls(const char *name, struct fileinfo *fp)
 171 {       int rc;
 172         int nacl;
 173         aclent_t acls[4], *list;
 174 
 175         if (fp->f_numacls == 0) {
 176                 /* fabricate a standard set of bogus ACLs */
 177                 acls[0].a_type = USER_OBJ;
 178                 acls[0].a_id = fp->f_uid;
 179                 acls[0].a_perm = (fp->f_mode >> 6) & 7;
 180 
 181                 acls[1].a_type = GROUP_OBJ;
 182                 acls[1].a_id = fp->f_gid;
 183                 acls[1].a_perm = (fp->f_mode >> 3) & 7;
 184 
 185                 acls[2].a_type = CLASS_OBJ;
 186                 acls[2].a_id = 0;
 187                 acls[2].a_perm = (fp->f_mode >> 6) & 7;
 188 
 189                 acls[3].a_type = OTHER_OBJ;
 190                 acls[3].a_id = 0;
 191                 acls[3].a_perm = fp->f_mode & 7;
 192 
 193                 nacl = 4;
 194                 list = acls;
 195         } else {
 196                 nacl = fp->f_numacls;
 197                 list = fp->f_acls;
 198         }
 199 
 200         rc = acl(name, SETACL, nacl, list);
 201 
 202         /* non-negative number mean success             */
 203         if (rc < 0)
 204                 return (rc);
 205         else
 206                 return (0);
 207 }
 208 
 209 /*
 210  * routine:
 211  *      show_acls
 212  *
 213  * purpose:
 214  *      to map an acl into arguments for a setfacl command
 215  *
 216  * paramters:
 217  *      number of elements in list
 218  *      pointer to list
 219  *
 220  * returns:
 221  *      pointer to character buffer containing arguments
 222  */
 223 char
 224 *show_acls(int numacl, aclent_t *list)
 225 {       int i, j;
 226         int type, perm, id;
 227         char *s;
 228         static char buf[ MAX_LINE ];
 229 
 230         s = buf;
 231 
 232         if (numacl > 0) {
 233                 *s++ = '-';
 234                 *s++ = 's';
 235                 *s++ = ' ';
 236         } else {
 237                 *s++ = '-';
 238                 *s++ = 'd';
 239         }
 240 
 241         for (i = 0; i < numacl; i++) {
 242                 type = list[i].a_type;
 243                 id = list[i].a_id;
 244                 perm = list[i].a_perm;
 245 
 246                 if (i > 0)
 247                         *s++ = ',';
 248 
 249                 /* note whether this is per-file or default     */
 250                 if (type & ACL_DEFAULT) {
 251                         *s++ = 'd';
 252                         *s++ = ':';
 253                 }
 254 
 255                 /* print out the entry type                     */
 256                 if (type & (USER_OBJ|USER)) {
 257                         *s++ = 'u';
 258                         *s++ = ':';
 259                 } else if (type & (GROUP_OBJ|GROUP)) {
 260                         *s++ = 'g';
 261                         *s++ = ':';
 262                 } else if (type & OTHER_OBJ) {
 263                         *s++ = 'o';
 264                         *s++ = ':';
 265                 } else if (type & CLASS_OBJ) {
 266                         *s++ = 'm';
 267                         *s++ = ':';
 268                 }
 269 
 270                 /* print out the ID for this ACL                */
 271                 if (type & (USER_OBJ|GROUP_OBJ))
 272                         *s++ = ':';
 273                 else if (type & (USER|GROUP)) {
 274                         for (j = 1; id/j > 10; j *= 10);
 275 
 276                         while (j > 0) {
 277                                 *s++ = '0' + (id/j);
 278                                 id %= j*10;
 279                                 j /= 10;
 280                         }
 281 
 282                         *s++ = ':';
 283                 }
 284 
 285                 /* print out the permissions for this ACL       */
 286                 *s++ = (perm & 04) ? 'r' : '-';
 287                 *s++ = (perm & 02) ? 'w' : '-';
 288                 *s++ = (perm & 01) ? 'x' : '-';
 289         }
 290 
 291         *s = 0;
 292         return (buf);
 293 }