]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/filed/acl.c
Add rudimentary support for saving AFS acls.
[bacula/bacula] / bacula / src / filed / acl.c
index 2570fa1487fd74dea4b9895671ea136ded689d02..b83bd7a19ef63a643e33611e3831750e09bf6cb2 100644 (file)
@@ -38,6 +38,8 @@
  *   - Solaris (POSIX and NFSv4/ZFS acls)
  *   - Tru64
  *
+ * Next to OS specific acls we support AFS acls using the pioctl interface.
+ *
  * We handle two different types of ACLs: access and default ACLS.
  * On most systems that support default ACLs they only apply to directories.
  *
@@ -63,7 +65,7 @@
 #include "bacula.h"
 #include "filed.h"
   
-#if !defined(HAVE_ACL)
+#if !defined(HAVE_ACL) && !defined(HAVE_AFS_ACL)
 /**
  * Entry points when compiled without support for ACLs or on an unsupported platform.
  */
@@ -193,7 +195,6 @@ static int os_default_acl_streams[1] = {
 
 static bacl_exit_code aix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
 {
-   berrno be;
    mode_t mode;
    acl_type_t type;
    size_t aclsize, acltxtsize;
@@ -206,6 +207,8 @@ static bacl_exit_code aix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
    memset(&type, 0, sizeof(acl_type_t));
    type.u64 = ACL_ANY;
    if (aclx_get(jcr->last_fname, GET_ACLINFO_ONLY, &type, NULL, &aclsize, &mode) < 0) {
+      berrno be;
+
       switch (errno) {
       case ENOENT:
          retval = bacl_exit_ok;
@@ -239,6 +242,8 @@ static bacl_exit_code aix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
     * Retrieve the ACL info.
     */
    if (aclx_get(jcr->last_fname, 0, &type, aclbuf, &aclsize, &mode) < 0) {
+      berrno be;
+
       switch (errno) {
       case ENOENT:
          retval = bacl_exit_ok;
@@ -358,7 +363,6 @@ static bacl_exit_code aix_parse_acl_streams(JCR *jcr,
                                             uint32_t content_length)
 {
    int cnt;
-   berrno be;
    acl_type_t type;
    size_t aclsize;
    bacl_exit_code retval = bacl_exit_error;
@@ -402,6 +406,8 @@ static bacl_exit_code aix_parse_acl_streams(JCR *jcr,
    aclbuf = check_pool_memory_size(aclbuf, content_length);
    aclsize = content_length;
    if (aclx_scanStr(content, aclbuf, &aclsize, type) < 0) {
+      berrno be;
+
       switch (errno) {
       case ENOSPC:
          /*
@@ -427,11 +433,13 @@ static bacl_exit_code aix_parse_acl_streams(JCR *jcr,
                if (cnt < 3) {
                   continue;
                }
-               /* FALL THROUGH */
+               /*
+                * FALLTHROUGH
+                */
             default:
                Mmsg2(jcr->errmsg,
                      _("aclx_scanStr error on file \"%s\": ERR=%s\n"),
-                     jcr->last_fname, be.bstrerror());
+                     jcr->last_fname, be.bstrerror(errno));
                Dmsg2(100, "aclx_scanStr error file=%s ERR=%s\n",
                      jcr->last_fname, be.bstrerror());
                goto bail_out;
@@ -448,6 +456,8 @@ static bacl_exit_code aix_parse_acl_streams(JCR *jcr,
    }
 
    if (aclx_put(jcr->last_fname, SET_ACL, type, aclbuf, aclsize, 0) < 0) {
+      berrno be;
+
       switch (errno) {
       case ENOENT:
          retval = bacl_exit_ok;
@@ -748,7 +758,6 @@ static bacl_exit_code generic_get_acl_from_os(JCR *jcr, bacl_type acltype)
    acl_t acl;
    acl_type_t ostype;
    char *acl_text;
-   berrno be;
    bacl_exit_code retval = bacl_exit_ok;
 
    ostype = bac_to_os_acltype(acltype);
@@ -805,6 +814,7 @@ static bacl_exit_code generic_get_acl_from_os(JCR *jcr, bacl_type acltype)
          return bacl_exit_ok;
       }
 
+      berrno be;
       Mmsg2(jcr->errmsg,
             _("acl_to_text error on file \"%s\": ERR=%s\n"),
             jcr->last_fname, be.bstrerror());
@@ -814,6 +824,8 @@ static bacl_exit_code generic_get_acl_from_os(JCR *jcr, bacl_type acltype)
       retval = bacl_exit_error;
       goto bail_out;
    } else {
+      berrno be;
+
       /*
        * Handle errors gracefully.
        */
@@ -863,7 +875,6 @@ static bacl_exit_code generic_set_acl_on_os(JCR *jcr,
 {
    acl_t acl;
    acl_type_t ostype;
-   berrno be;
 
    /*
     * If we get empty default ACLs, clear ACLs now
@@ -873,6 +884,8 @@ static bacl_exit_code generic_set_acl_on_os(JCR *jcr,
       if (acl_delete_def_file(jcr->last_fname) == 0) {
          return bacl_exit_ok;
       }
+      berrno be;
+
       switch (errno) {
       case ENOENT:
          return bacl_exit_ok;
@@ -900,6 +913,8 @@ static bacl_exit_code generic_set_acl_on_os(JCR *jcr,
 
    acl = acl_from_text(content);
    if (acl == NULL) {
+      berrno be;
+
       Mmsg2(jcr->errmsg,
             _("acl_from_text error on file \"%s\": ERR=%s\n"),
             jcr->last_fname, be.bstrerror());
@@ -914,6 +929,8 @@ static bacl_exit_code generic_set_acl_on_os(JCR *jcr,
     * As it does the right thing, given valid input, just ignore acl_valid().
     */
    if (acl_valid(acl) != 0) {
+      berrno be;
+
       Mmsg2(jcr->errmsg,
             _("acl_valid error on file \"%s\": ERR=%s\n"),
             jcr->last_fname, be.bstrerror());
@@ -931,6 +948,8 @@ static bacl_exit_code generic_set_acl_on_os(JCR *jcr,
     * don't save acls of symlinks (which cannot have acls anyhow)
     */
    if (acl_set_file(jcr->last_fname, ostype, acl) != 0 && jcr->last_type != FT_LNK) {
+      berrno be;
+
       switch (errno) {
       case ENOENT:
          acl_free(acl);
@@ -1046,7 +1065,6 @@ static bacl_exit_code freebsd_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
 {
    int acl_enabled = 0;
    bacl_type acltype = BACL_TYPE_NONE;
-   berrno be;
 
 #if defined(_PC_ACL_NFS4)
    /*
@@ -1054,7 +1072,9 @@ static bacl_exit_code freebsd_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
     */
    acl_enabled = pathconf(jcr->last_fname, _PC_ACL_NFS4);
    switch (acl_enabled) {
-   case -1:
+   case -1: {
+      berrno be;
+
       switch (errno) {
       case ENOENT:
          return bacl_exit_ok;
@@ -1066,6 +1086,7 @@ static bacl_exit_code freebsd_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
                jcr->last_fname, be.bstrerror());
          return bacl_exit_error;
       }
+   }
    case 0:
       break;
    default:
@@ -1080,7 +1101,9 @@ static bacl_exit_code freebsd_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
        */
       acl_enabled = pathconf(jcr->last_fname, _PC_ACL_EXTENDED);
       switch (acl_enabled) {
-      case -1:
+      case -1: {
+         berrno be;
+
          switch (errno) {
          case ENOENT:
             return bacl_exit_ok;
@@ -1092,6 +1115,7 @@ static bacl_exit_code freebsd_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
                   jcr->last_fname, be.bstrerror());
             return bacl_exit_error;
          }
+      }
       case 0:
          break;
       default:
@@ -1167,7 +1191,6 @@ static bacl_exit_code freebsd_parse_acl_streams(JCR *jcr,
 {
    int acl_enabled = 0;
    const char *acl_type_name;
-   berrno be;
 
    /*
     * First make sure the filesystem supports acls.
@@ -1192,7 +1215,9 @@ static bacl_exit_code freebsd_parse_acl_streams(JCR *jcr,
    }
 
    switch (acl_enabled) {
-   case -1:
+   case -1: {
+      berrno be;
+
       switch (errno) {
       case ENOENT:
          return bacl_exit_ok;
@@ -1204,6 +1229,7 @@ static bacl_exit_code freebsd_parse_acl_streams(JCR *jcr,
                content, jcr->last_fname, be.bstrerror());
          return bacl_exit_error;
       }
+   }
    case 0:
       /*
        * If the filesystem reports it doesn't support ACLs we clear the
@@ -1464,9 +1490,10 @@ static bacl_exit_code hpux_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
    int n;
    struct acl_entry acls[NACLENTRIES];
    char *acl_text;
-   berrno be;
 
    if ((n = getacl(jcr->last_fname, 0, acls)) < 0) {
+      berrno be;
+
       switch (errno) {
 #if defined(BACL_ENOTSUP)
       case BACL_ENOTSUP:
@@ -1521,6 +1548,8 @@ static bacl_exit_code hpux_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
 
          return send_acl_stream(jcr, STREAM_ACL_HPUX_ACL_ENTRY);
       }
+
+      berrno be;
       Mmsg2(jcr->errmsg,
             _("acltostr error on file \"%s\": ERR=%s\n"),
             jcr->last_fname, be.bstrerror());
@@ -1538,10 +1567,11 @@ static bacl_exit_code hpux_parse_acl_streams(JCR *jcr,
 {
    int n, stat;
    struct acl_entry acls[NACLENTRIES];
-   berrno be;
 
    n = strtoacl(content, 0, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP);
    if (n <= 0) {
+      berrno be;
+
       Mmsg2(jcr->errmsg,
             _("strtoacl error on file \"%s\": ERR=%s\n"),
             jcr->last_fname, be.bstrerror());
@@ -1550,6 +1580,8 @@ static bacl_exit_code hpux_parse_acl_streams(JCR *jcr,
       return bacl_exit_error;
    }
    if (strtoacl(content, n, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP) != n) {
+      berrno be;
+
       Mmsg2(jcr->errmsg,
             _("strtoacl error on file \"%s\": ERR=%s\n"),
             jcr->last_fname, be.bstrerror());
@@ -1564,8 +1596,9 @@ static bacl_exit_code hpux_parse_acl_streams(JCR *jcr,
     * This is only true for the old acl streams as in the new implementation we
     * don't save acls of symlinks (which cannot have acls anyhow)
     */
-   if (setacl(jcr->last_fname, n, acls) != 0 &&
-       jcr->last_type != FT_LNK) {
+   if (setacl(jcr->last_fname, n, acls) != 0 && jcr->last_type != FT_LNK) {
+      berrno be;
+
       switch (errno) {
       case ENOENT:
          return bacl_exit_ok;
@@ -1665,7 +1698,6 @@ static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
    acl_t *aclp;
    char *acl_text;
    bacl_exit_code stream_status = bacl_exit_error;
-   berrno be;
 
    /*
     * See if filesystem supports acls.
@@ -1683,7 +1715,9 @@ static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
       pm_strcpy(jcr->acl_data->u.build->content, "");
       jcr->acl_data->u.build->content_length = 0;
       return bacl_exit_ok;
-   case -1:
+   case -1: {
+      berrno be;
+
       switch (errno) {
       case ENOENT:
          return bacl_exit_ok;
@@ -1695,6 +1729,7 @@ static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
                jcr->last_fname, be.bstrerror());
          return bacl_exit_error;
       }
+   }
    default:
       break;
    }
@@ -1703,6 +1738,8 @@ static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
     * Get ACL info: don't bother allocating space if there is only a trivial ACL.
     */
    if (acl_get(jcr->last_fname, ACL_NO_TRIVIAL, &aclp) != 0) {
+      berrno be;
+
       switch (errno) {
       case ENOENT:
          return bacl_exit_ok;
@@ -1763,7 +1800,6 @@ static bacl_exit_code solaris_parse_acl_streams(JCR *jcr,
 {
    acl_t *aclp;
    int acl_enabled, error;
-   berrno be;
 
    switch (stream) {
    case STREAM_UNIX_ACCESS_ACL:
@@ -1786,7 +1822,9 @@ static bacl_exit_code solaris_parse_acl_streams(JCR *jcr,
                _("Trying to restore acl on file \"%s\" on filesystem without acl support\n"),
                jcr->last_fname);
          return bacl_exit_error;
-      case -1:
+      case -1: {
+         berrno be;
+
          switch (errno) {
          case ENOENT:
             return bacl_exit_ok;
@@ -1798,6 +1836,7 @@ static bacl_exit_code solaris_parse_acl_streams(JCR *jcr,
                   content, jcr->last_fname, be.bstrerror());
             return bacl_exit_error;
          }
+      }
       default:
          /*
           * On a filesystem with ACL support make sure this particular ACL type can be restored.
@@ -1940,11 +1979,11 @@ static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
    int n;
    aclent_t *acls;
    char *acl_text;
-   berrno be;
 
    n = acl(jcr->last_fname, GETACLCNT, 0, NULL);
-   if (n < MIN_ACL_ENTRIES)
+   if (n < MIN_ACL_ENTRIES) {
       return bacl_exit_error;
+   }
 
    acls = (aclent_t *)malloc(n * sizeof(aclent_t));
    if (acl(jcr->last_fname, GETACL, n, acls) == n) {
@@ -1967,6 +2006,7 @@ static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
          return send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
       }
 
+      berrno be;
       Mmsg2(jcr->errmsg,
             _("acltotext error on file \"%s\": ERR=%s\n"),
             jcr->last_fname, be.bstrerror());
@@ -1985,10 +2025,11 @@ static bacl_exit_code solaris_parse_acl_streams(JCR *jcr,
 {
    int n;
    aclent_t *acls;
-   berrno be;
 
    acls = aclfromtext(content, &n);
    if (!acls) {
+      berrno be;
+
       Mmsg2(jcr->errmsg,
             _("aclfromtext error on file \"%s\": ERR=%s\n"),
             jcr->last_fname, be.bstrerror());
@@ -2002,6 +2043,8 @@ static bacl_exit_code solaris_parse_acl_streams(JCR *jcr,
     * not have attributes, and the file it is linked to may not yet be restored.
     */
    if (acl(jcr->last_fname, SETACL, n, acls) == -1 && jcr->last_type != FT_LNK) {
+      berrno be;
+
       switch (errno) {
       case ENOENT:
          actuallyfree(acls);
@@ -2034,7 +2077,86 @@ static bacl_exit_code (*os_parse_acl_streams)
 #endif /* HAVE_SUN_OS */
 #endif /* HAVE_ACL */
 
-/*
+#if defined(HAVE_AFS_ACL)
+
+#if defined(HAVE_AFS_AFSINT_H) && defined(HAVE_AFS_VENUS_H)
+#include <afs/afsint.h>
+#include <afs/venus.h>
+#else
+#error "configure failed to detect availability of afs/afsint.h and/or afs/venus.h"
+#endif
+
+/**
+ * External references to functions in the libsys library function not in current include files.
+ */
+extern "C" {
+long pioctl(char *pathp, long opcode, struct ViceIoctl *blobp, int follow);
+}
+
+static bacl_exit_code afs_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
+{
+   int error;
+   struct ViceIoctl vip;
+   char acl_text[BUFSIZ];
+
+   /*
+    * AFS ACLs can only be set on a directory, so no need to try to
+    * request them for anything other then that.
+    */
+   if (ff_pkt->type != FT_DIREND) {
+      return bacl_exit_ok;
+   }
+
+   vip.in = NULL;
+   vip.in_size = 0;
+   vip.out = acl_text;
+   vip.out_size = sizeof(acl_text);
+   memset((caddr_t)acl_text, 0, sizeof(acl_text));
+
+   if ((error = pioctl(jcr->last_fname, VIOCGETAL, &vip, 0)) < 0) {
+      berrno be;
+
+      Mmsg2(jcr->errmsg,
+            _("pioctl VIOCGETAL error on file \"%s\": ERR=%s\n"),
+            jcr->last_fname, be.bstrerror());
+      Dmsg2(100, "pioctl VIOCGETAL error file=%s ERR=%s\n",
+            jcr->last_fname, be.bstrerror());
+      return bacl_exit_error;
+   }
+   jcr->acl_data->u.build->content_length =
+   pm_strcpy(jcr->acl_data->u.build->content, acl_text);
+   return send_acl_stream(jcr, STREAM_ACL_AFS_TEXT);
+}
+
+static bacl_exit_code afs_parse_acl_stream(JCR *jcr,
+                                           int stream,
+                                           char *content,
+                                           uint32_t content_length)
+{
+   int error;
+   struct ViceIoctl vip;
+
+   vip.in = content;
+   vip.in_size = content_length;
+   vip.out = NULL;
+   vip.out_size = 0;
+
+   if ((error = pioctl(jcr->last_fname, VIOCSETAL, &vip, 0)) < 0) {
+      berrno be;
+
+      Mmsg2(jcr->errmsg,
+            _("pioctl VIOCSETAL error on file \"%s\": ERR=%s\n"),
+            jcr->last_fname, be.bstrerror());
+      Dmsg2(100, "pioctl VIOCSETAL error file=%s ERR=%s\n",
+            jcr->last_fname, be.bstrerror());
+
+      return bacl_exit_error;
+   }
+   return bacl_exit_ok;
+}
+#endif /* HAVE_AFS_ACL */
+
+/**
  * Entry points when compiled with support for ACLs on a supported platform.
  */
 
@@ -2045,7 +2167,7 @@ bacl_exit_code build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
 {
    /*
     * See if we are changing from one device to an other.
-    * We save the current device we are restoring to and compare
+    * We save the current device we are scanning and compare
     * it with the current st_dev in the last stat performed on
     * the file we are currently storing.
     */
@@ -2055,14 +2177,35 @@ bacl_exit_code build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
        */
       jcr->acl_data->flags = 0;
 
+#if defined(HAVE_AFS_ACL)
+      /*
+       * AFS is a non OS specific filesystem so see if this path is on an AFS filesystem
+       * Set the BACL_FLAG_SAVE_AFS flag if it is. If not set the BACL_FLAG_SAVE_NATIVE flag.
+       */
+      if (fstype_equals(jcr->last_fname, "afs")) {
+         jcr->acl_data->flags |= BACL_FLAG_SAVE_AFS;
+      } else {
+         jcr->acl_data->flags |= BACL_FLAG_SAVE_NATIVE;
+      }
+#else
       jcr->acl_data->flags |= BACL_FLAG_SAVE_NATIVE;
+#endif
 
-      /**
+      /*
        * Save that we started scanning a new filesystem.
        */
       jcr->acl_data->current_dev = ff_pkt->statp.st_dev;
    }
 
+#if defined(HAVE_AFS_ACL)
+   /*
+    * See if the BACL_FLAG_SAVE_AFS flag is set which lets us know if we should
+    * save AFS ACLs.
+    */
+   if (jcr->acl_data->flags & BACL_FLAG_SAVE_AFS) {
+      return afs_build_acl_streams(jcr, ff_pkt);
+   }
+#endif
 #if defined(HAVE_ACL)
    /*
     * See if the BACL_FLAG_SAVE_NATIVE flag is set which lets us know if we should
@@ -2088,7 +2231,6 @@ bacl_exit_code parse_acl_streams(JCR *jcr,
                                  uint32_t content_length)
 {
    int ret;
-   berrno be;
    struct stat st;
    unsigned int cnt;
 
@@ -2100,7 +2242,9 @@ bacl_exit_code parse_acl_streams(JCR *jcr,
     */
    ret = lstat(jcr->last_fname, &st);
    switch (ret) {
-   case -1:
+   case -1: {
+      berrno be;
+
       switch (errno) {
       case ENOENT:
          return bacl_exit_ok;
@@ -2113,6 +2257,7 @@ bacl_exit_code parse_acl_streams(JCR *jcr,
          return bacl_exit_error;
       }
       break;
+   }
    case 0:
       break;
    }
@@ -2121,7 +2266,20 @@ bacl_exit_code parse_acl_streams(JCR *jcr,
        * Reset the acl save flags.
        */
       jcr->acl_data->flags = 0;
+
+#if defined(HAVE_AFS_ACL)
+      /*
+       * AFS is a non OS specific filesystem so see if this path is on an AFS filesystem
+       * Set the BACL_FLAG_RESTORE_AFS flag if it is. If not set the BACL_FLAG_RETORE_NATIVE flag.
+       */
+      if (fstype_equals(jcr->last_fname, "afs")) {
+         jcr->acl_data->flags |= BACL_FLAG_RESTORE_AFS;
+      } else {
+         jcr->acl_data->flags |= BACL_FLAG_RESTORE_NATIVE;
+      }
+#else
       jcr->acl_data->flags |= BACL_FLAG_RESTORE_NATIVE;
+#endif
 
       /*
        * Save that we started restoring to a new filesystem.
@@ -2130,6 +2288,18 @@ bacl_exit_code parse_acl_streams(JCR *jcr,
    }
 
    switch (stream) {
+#if defined(HAVE_AFS_ACL)
+   case STREAM_ACL_AFS_TEXT:
+      if (jcr->acl_data->flags & BACL_FLAG_RESTORE_AFS) {
+         return afs_parse_acl_stream(jcr, stream, content, content_length);
+      } else {
+         /*
+          * Increment error count but don't log an error again for the same filesystem.
+          */
+         jcr->acl_data->u.parse->nr_errors++;
+         return bacl_exit_ok;
+      }
+#endif
 #if defined(HAVE_ACL)
    case STREAM_UNIX_ACCESS_ACL:
    case STREAM_UNIX_DEFAULT_ACL: