]> arthur.barton.de Git - netatalk.git/blobdiff - etc/afpd/acls.c
Merge from branch-2-1
[netatalk.git] / etc / afpd / acls.c
index 195f164530d6807a75098d3471c2b0005c44423e..c8269c6a7fdb2fdf253526744d1d3562b2630805 100644 (file)
@@ -316,6 +316,7 @@ int map_aces_darwin_to_solaris(darwin_ace_t *darwin_aces, ace_t *nfsv4_aces, int
             pwd = getpwnam(name);
             if (!pwd) {
                 LOG(log_error, logtype_afpd, "map_aces_darwin_to_solaris: getpwnam: %s", strerror(errno));
+                free(name);
                 return -1;
             }
             nfsv4_aces->a_who = pwd->pw_uid;
@@ -323,6 +324,7 @@ int map_aces_darwin_to_solaris(darwin_ace_t *darwin_aces, ace_t *nfsv4_aces, int
             grp = getgrnam(name);
             if (!grp) {
                 LOG(log_error, logtype_afpd, "map_aces_darwin_to_solaris: getgrnam: %s", strerror(errno));
+                free(name);
                 return -1;
             }
             nfsv4_aces->a_who = (uid_t)(grp->gr_gid);
@@ -369,7 +371,7 @@ int map_aces_darwin_to_solaris(darwin_ace_t *darwin_aces, ace_t *nfsv4_aces, int
 }
 #endif /* HAVE_SOLARIS_ACLS */
 
-/* 
+/*
  * Map ACEs from POSIX to Darwin.
  * type is either POSIX_DEFAULT_2_DARWIN or POSIX_ACCESS_2_DARWIN, cf. acl_get_file.
  * Return number of mapped ACES, -1 on error.
@@ -378,72 +380,93 @@ int map_aces_darwin_to_solaris(darwin_ace_t *darwin_aces, ace_t *nfsv4_aces, int
 static int map_acl_posix_to_darwin(int type, const acl_t acl, darwin_ace_t *darwin_aces)
 {
     int mapped_aces = 0;
+    int havemask = 0;
     int entry_id = ACL_FIRST_ENTRY;
     acl_entry_t e;
     acl_tag_t tag;
-    acl_permset_t permset;
-    uid_t *uid;
-    gid_t *gid;
+    acl_permset_t permset, mask;
+    uid_t *uid = NULL;
+    gid_t *gid = NULL;
     struct passwd *pwd = NULL;
     struct group *grp = NULL;
     uint32_t flags;
     uint32_t rights;
+    darwin_ace_t *saved_darwin_aces = darwin_aces;
 
-    LOG(log_maxdebug, logtype_afpd, "map_aces_posix_to_darwin(%s)", 
-        type == POSIX_DEFAULT_2_DARWIN ?
+    LOG(log_maxdebug, logtype_afpd, "map_aces_posix_to_darwin(%s)",
+        (type & MAP_MASK) == POSIX_DEFAULT_2_DARWIN ?
         "POSIX_DEFAULT_2_DARWIN" : "POSIX_ACCESS_2_DARWIN");
 
+    /* itereate through all ACEs */
     while (acl_get_entry(acl, entry_id, &e) == 1) {
         entry_id = ACL_NEXT_ENTRY;
 
+        /* get ACE type */
         if (acl_get_tag_type(e, &tag) != 0) {
-            LOG(log_error, logtype_afpd, "map_aces_posix_to_darwin: acl_get_tag_type: %s",
-                strerror(errno));
-        }            
+            LOG(log_error, logtype_afpd, "map_aces_posix_to_darwin: acl_get_tag_type: %s", strerror(errno));
+            mapped_aces = -1;
+            goto exit;
+        }
 
+        /* we return user and group ACE */
         switch (tag) {
         case ACL_USER:
             if ((uid = (uid_t *)acl_get_qualifier(e)) == NULL) {
-                LOG(log_error, logtype_afpd, "map_aces_posix_to_darwin: acl_get_qualifier: %s", 
+                LOG(log_error, logtype_afpd, "map_aces_posix_to_darwin: acl_get_qualifier: %s",
                     strerror(errno));
-                return -1;
+                mapped_aces = -1;
+                goto exit;
             }
-            pwd = getpwuid(*uid);
-            if (!pwd) {
+            if ((pwd = getpwuid(*uid)) == NULL) {
                 LOG(log_error, logtype_afpd, "map_aces_posix_to_darwin: getpwuid error: %s",
                     strerror(errno));
-                return -1;
+                mapped_aces = -1;
+                goto exit;
             }
             LOG(log_debug, logtype_afpd, "map_aces_posix_to_darwin: uid: %d -> name: %s",
-               *uid, pwd->pw_name);
+                *uid, pwd->pw_name);
             if (getuuidfromname(pwd->pw_name, UUID_USER, darwin_aces->darwin_ace_uuid) != 0) {
                 LOG(log_error, logtype_afpd, "map_aces_posix_to_darwin: getuuidfromname error");
-                return -1;
+                mapped_aces = -1;
+                goto exit;
             }
             acl_free(uid);
+            uid = NULL;
             break;
 
         case ACL_GROUP:
             if ((gid = (gid_t *)acl_get_qualifier(e)) == NULL) {
-                LOG(log_error, logtype_afpd, "map_aces_posix_to_darwin: acl_get_qualifier: %s", 
+                LOG(log_error, logtype_afpd, "map_aces_posix_to_darwin: acl_get_qualifier: %s",
                     strerror(errno));
-                return -1;
+                mapped_aces = -1;
+                goto exit;
             }
-            grp = getgrgid(*gid);
-            if (!grp) {
+            if ((grp = getgrgid(*gid)) == NULL) {
                 LOG(log_error, logtype_afpd, "map_aces_posix_to_darwin: getgrgid error: %s",
                     strerror(errno));
-                return -1;
+                mapped_aces = -1;
+                goto exit;
             }
             LOG(log_debug, logtype_afpd, "map_aces_posix_to_darwin: gid: %d -> name: %s",
                 *gid, grp->gr_name);
             if (getuuidfromname(grp->gr_name, UUID_GROUP, darwin_aces->darwin_ace_uuid) != 0) {
                 LOG(log_error, logtype_afpd, "map_aces_solaris_to_darwin: getuuidfromname error");
-                return -1;
+                mapped_aces = -1;
+                goto exit;
             }
-
+            acl_free(gid);
+            gid = NULL;
             break;
 
+            /* store mask so we can apply it later in a second loop */
+        case ACL_MASK:
+            if (acl_get_permset(e, &mask) != 0) {
+                LOG(log_error, logtype_afpd, "map_aces_solaris_to_darwin: acl_get_permset: %s", strerror(errno));
+                return -1;
+            }
+            havemask = 1;
+            continue;
+
         default:
             continue;
         }
@@ -457,13 +480,14 @@ static int map_acl_posix_to_darwin(int type, const acl_t acl, darwin_ace_t *darw
         darwin_aces->darwin_ace_flags = htonl(flags);
 
         /* rights */
-        rights = 0;
         if (acl_get_permset(e, &permset) != 0) {
+            LOG(log_error, logtype_afpd, "map_aces_solaris_to_darwin: acl_get_permset: %s", strerror(errno));
             return -1;
         }
 
+        rights = 0;
         if (acl_get_perm(permset, ACL_READ))
-            rights |= DARWIN_ACE_READ_DATA
+            rights = DARWIN_ACE_READ_DATA
                 | DARWIN_ACE_READ_EXTATTRIBUTES
                 | DARWIN_ACE_READ_ATTRIBUTES
                 | DARWIN_ACE_READ_SECURITY;
@@ -472,7 +496,7 @@ static int map_acl_posix_to_darwin(int type, const acl_t acl, darwin_ace_t *darw
                 | DARWIN_ACE_APPEND_DATA
                 | DARWIN_ACE_WRITE_EXTATTRIBUTES
                 | DARWIN_ACE_WRITE_ATTRIBUTES;
-            if ((type & MAP_MASK) == IS_DIR)
+            if ((type & ~MAP_MASK) == IS_DIR)
                 rights |= DARWIN_ACE_DELETE;
         }
         if (acl_get_perm(permset, ACL_EXECUTE))
@@ -482,13 +506,42 @@ static int map_acl_posix_to_darwin(int type, const acl_t acl, darwin_ace_t *darw
 
         darwin_aces++;
         mapped_aces++;
+    } /* while */
+
+    if (havemask) {
+        /* Loop through the mapped ACE buffer once again, applying the mask */
+        /* Map the mask to Darwin ACE rights first */
+        rights = 0;
+        if (acl_get_perm(mask, ACL_READ))
+            rights = DARWIN_ACE_READ_DATA
+                | DARWIN_ACE_READ_EXTATTRIBUTES
+                | DARWIN_ACE_READ_ATTRIBUTES
+                | DARWIN_ACE_READ_SECURITY;
+        if (acl_get_perm(mask, ACL_WRITE)) {
+            rights |= DARWIN_ACE_WRITE_DATA
+                | DARWIN_ACE_APPEND_DATA
+                | DARWIN_ACE_WRITE_EXTATTRIBUTES
+                | DARWIN_ACE_WRITE_ATTRIBUTES;
+            if ((type & ~MAP_MASK) == IS_DIR)
+                rights |= DARWIN_ACE_DELETE;
+        }
+        if (acl_get_perm(mask, ACL_EXECUTE))
+            rights |= DARWIN_ACE_EXECUTE;
+        for (int i = mapped_aces; i > 0; i--) {
+            saved_darwin_aces->darwin_ace_rights &= htonl(rights);
+            saved_darwin_aces++;
+        }
     }
 
+exit:
+    if (uid) acl_free(uid);
+    if (gid) acl_free(gid);
+
     return mapped_aces;
 }
 #endif
 
-/*  
+/*
  * Multiplex ACL mapping (SOLARIS_2_DARWIN, DARWIN_2_SOLARIS, POSIX_2_DARWIN, DARWIN_2_POSIX).
  * Reads from 'aces' buffer, writes to 'rbuf' buffer.
  * Caller must provide buffer.
@@ -580,37 +633,31 @@ static int get_and_map_acl(char *name, char *rbuf, size_t *rbuflen)
         err = -1;
         goto cleanup;
     }
-    
+
     /* if its a dir, check for default acl too */
     dirflag = 0;
     if (S_ISDIR(st.st_mode)) {
         dirflag = IS_DIR;
-        if ((defacl = acl_get_file(name, ACL_TYPE_DEFAULT)) == NULL && errno != ENOTDIR) {
-            LOG(log_error, logtype_afpd, "get_and_map_acl: couldnt get default ACL");
-            err = -1;
-            goto cleanup;
-        }
+        if ((defacl = acl_get_file(name, ACL_TYPE_DEFAULT)) == NULL) {
+            LOG(log_error, logtype_afpd, "get_and_map_acl: couldnt get default ACL"); err = -1; goto cleanup;
+        }        
         if (defacl && (mapped_aces = map_acl(POSIX_DEFAULT_2_DARWIN | dirflag,
                                              defacl,
                                              (darwin_ace_t *)rbuf,
                                              0)) == -1) {
-            err = -1;
-            goto cleanup;
+            err = -1; goto cleanup;
         }
     }
 
     if ((accacl = acl_get_file(name, ACL_TYPE_ACCESS)) == NULL) {
-        LOG(log_error, logtype_afpd, "get_and_map_acl: couldnt get access ACL");
-        err = -1;
-        goto cleanup;
+        LOG(log_error, logtype_afpd, "get_and_map_acl: couldnt get access ACL"); err = -1; goto cleanup;
     }
 
     if (accacl && (mapped_aces += map_acl(POSIX_ACCESS_2_DARWIN | dirflag,
                                           accacl,
-                                          (darwin_ace_t *)rbuf + mapped_aces * sizeof(darwin_ace_t),
+                                          (darwin_ace_t *)(rbuf + mapped_aces * sizeof(darwin_ace_t)),
                                           0)) == -1) {
-        err = -1;
-        goto cleanup;
+        err = -1; goto cleanup;
     }
 #endif /* HAVE_POSIX_ACLS */
 
@@ -622,11 +669,11 @@ static int get_and_map_acl(char *name, char *rbuf, size_t *rbuflen)
 
 cleanup:
 #ifdef HAVE_SOLARIS_ACLS
-   free(aces);
+    free(aces);
 #endif
 #ifdef HAVE_POSIX_ACLS
-   if (defacl) acl_free(defacl);
-   if (accacl) acl_free(accacl);
+    if (defacl) acl_free(defacl);
+    if (accacl) acl_free(accacl);
 #endif /* HAVE_POSIX_ACLS */
 
     LOG(log_debug9, logtype_afpd, "get_and_map_acl: END");
@@ -636,13 +683,16 @@ cleanup:
 /* Removes all non-trivial ACLs from object. Returns full AFPERR code. */
 static int remove_acl(const struct vol *vol,const char *path, int dir)
 {
-    int ret;
+    int ret = AFP_OK;
 
+#ifdef HAVE_SOLARIS_ACLS
     /* Ressource etc. first */
     if ((ret = vol->vfs->vfs_remove_acl(vol, path, dir)) != AFP_OK)
         return ret;
     /* now the data fork or dir */
-    return (remove_acl_vfs(path));
+    ret = remove_acl_vfs(path);
+#endif
+    return ret;
 }
 
 /*
@@ -773,7 +823,7 @@ static int set_acl(const struct vol *vol, char *name, int inherit, char *ibuf)
 static int check_acl_access(const char *path, const uuidp_t uuid, uint32_t requested_darwin_rights)
 {
     int                 ret, i, ace_count, dir, checkgroup;
-    char                *username; /* might be group too */
+    char                *username = NULL; /* might be group too */
     uuidtype_t          uuidtype;
     uid_t               uid;
     gid_t               pgid;
@@ -850,6 +900,12 @@ static int check_acl_access(const char *path, const uuidp_t uuid, uint32_t reque
         ret = AFPERR_MISC;
         goto exit;
     }
+    if (ace_count == 0) {
+        LOG(log_debug, logtype_afpd, "check_access: 0 ACEs from get_nfsv4_acl");
+        ret = AFPERR_MISC;
+        goto exit;
+    }
+
     /* Now check requested rights */
     ret = AFPERR_ACCESS;
     i = 0;
@@ -932,6 +988,14 @@ exit:
 #ifdef HAVE_POSIX_ACLS
 static int check_acl_access(const char *path, const uuidp_t uuid, uint32_t requested_darwin_rights)
 {
+    /*
+     * FIXME: for OS X >= 10.6 it seems fp_access isn't called anymore, instead
+     * the client just tries to perform any action, relying on the server
+     * to enforce permission (which the OS does for us), returning appropiate
+     * error codes in case the action failed.
+     * So to summarize: I think it's safe to not implement this function and
+     * just always return AFP_OK.
+     */
     return AFP_OK;
 }
 #endif /* HAVE_POSIX_ACLS */
@@ -1166,8 +1230,11 @@ int afp_setacl(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size
             ret = set_acl(vol, s_path->u_name, 0, ibuf);
         if (ret == 0)
             ret = AFP_OK;
-        else
+        else {
+            LOG(log_warning, logtype_afpd, "afp_setacl(\"%s/%s\"): error",
+                getcwdpath(), s_path->u_name);
             ret = AFPERR_MISC;
+        }
     }
 
     LOG(log_debug9, logtype_afpd, "afp_setacl: END");
@@ -1180,7 +1247,7 @@ int afp_setacl(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size
 void acltoownermode(char *path, struct stat *st, uid_t uid, struct maccess *ma)
 {
     struct passwd *pw;
-    uuid_t uuid;
+    atalk_uuid_t uuid;
     int r_ok, w_ok, x_ok;
 
     if ( ! (AFPobj->options.flags & OPTION_UUID) || ! (AFPobj->options.flags & OPTION_ACL2OS9MODE))