]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/filed/acl.c
First compiling version of AIX 5.3 and later acl code using the new aclx_get and...
[bacula/bacula] / bacula / src / filed / acl.c
index b2a2e29eece8e8065eb476cfa93cddb7ea226a16..e3be782f3a328a1b22180128bfa5088090f1804d 100644 (file)
@@ -6,7 +6,7 @@
    The main author of Bacula is Kern Sibbald, with contributions from
    many others, a complete list can be found in the file AUTHORS.
    This program is Free Software; you can redistribute it and/or
-   modify it under the terms of version two of the GNU General Public
+   modify it under the terms of version three of the GNU Affero General Public
    License as published by the Free Software Foundation and included
    in the file LICENSE.
 
@@ -15,7 +15,7 @@
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Affero General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
@@ -126,6 +126,246 @@ static bacl_exit_code send_acl_stream(JCR *jcr, int stream)
 #if defined(HAVE_ACL)
 #if defined(HAVE_AIX_OS)
 
+#if defined(HAVE_EXTENDED_ACL)
+
+#include <sys/access.h>
+#include <sys/acl.h>
+
+static bool acl_is_trivial(struct acl *acl)
+{
+   return (acl_last(acl) != acl->acl_ext ? false : true);
+}
+
+static bool acl_nfs4_is_trivial(nfs4_acl_int_t *acl)
+{
+   return (acl->aclEntryN > 0 ? false : true);
+}
+
+/**
+ * Define the supported ACL streams for this OS
+ */
+static int os_access_acl_streams[3] = { STREAM_ACL_AIX_TEXT, STREAM_ACL_AIX_AIXC, STREAM_ACL_AIX_NFS4 };
+static int os_default_acl_streams[1] = { -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;
+   bacl_exit_code retval = bacl_exit_error;
+   POOLMEM *aclbuf = get_pool_memory(PM_MESSAGE);
+
+   /**
+    * First see how big the buffers should be.
+    */
+   type.u64 = ACL_ANY;
+   if (aclx_get(jcr->last_fname, GET_ACLINFO_ONLY, &type, NULL, &aclsize, NULL) < 0) {
+      switch (errno) {
+      case ENOENT:
+         retval = bacl_exit_ok;
+         goto bail_out;
+      default:
+         Mmsg2(jcr->errmsg, _("aclx_get error on file \"%s\": ERR=%s\n"),
+               jcr->last_fname, be.bstrerror());
+         Dmsg2(100, "aclx_get error file=%s ERR=%s\n",
+               jcr->last_fname, be.bstrerror());
+         goto bail_out;
+      }
+   }
+
+   /**
+    * Make sure the buffers are big enough.
+    */
+   aclbuf = check_pool_memory_size(aclbuf, aclsize + 1);
+
+   /**
+    * Retrieve the ACL info.
+    */
+   if (aclx_get(jcr->last_fname, 0, &type, aclbuf, &aclsize, &mode) < 0) {
+      switch (errno) {
+      case ENOENT:
+         retval = bacl_exit_ok;
+         goto bail_out;
+      default:
+         Mmsg2(jcr->errmsg, _("aclx_get error on file \"%s\": ERR=%s\n"),
+               jcr->last_fname, be.bstrerror());
+         Dmsg2(100, "aclx_get error file=%s ERR=%s\n",
+               jcr->last_fname, be.bstrerror());
+         goto bail_out;
+      }
+   }
+
+   /**
+    * See if the acl is non trivial.
+    */
+   switch (type.u64) {
+   case ACL_AIXC:
+      if (acl_is_trivial((struct acl *)aclbuf)) {
+         retval = bacl_exit_ok;
+         goto bail_out;
+      }
+      break;
+   case ACL_NFS4:
+      if (acl_nfs4_is_trivial((nfs4_acl_int_t *)aclbuf)) {
+         retval = bacl_exit_ok;
+         goto bail_out;
+      }
+      break;
+   default:
+      Mmsg2(jcr->errmsg, _("Unknown acl type encountered on file \"%s\": %ld\n"),
+            jcr->last_fname, type.u64);
+      Dmsg2(100, "Unknown acl type encountered on file \"%s\": %ld\n",
+            jcr->last_fname, type.u64);
+      goto bail_out;
+   }
+
+   /**
+    * We have a non-trivial acl lets convert it into some ASCII form.
+    */
+   acltxtsize = sizeof_pool_memory(jcr->acl_data->content);
+   if (aclx_printStr(jcr->acl_data->content, &acltxtsize, aclbuf,
+                     aclsize, type, jcr->last_fname, 0) < 0) {
+      switch (errno) {
+      case ENOSPC:
+         /**
+          * Our buffer is not big enough, acltxtsize should be updated with the value
+          * the aclx_printStr really need. So we increase the buffer and try again.
+          */
+         jcr->acl_data->content = check_pool_memory_size(jcr->acl_data->content, acltxtsize + 1);
+         if (aclx_printStr(jcr->acl_data->content, &acltxtsize, aclbuf,
+                           aclsize, type, jcr->last_fname, 0) < 0) {
+            Mmsg1(jcr->errmsg, _("Failed to convert acl into text on file \"%s\"\n"),
+                  jcr->last_fname);
+            Dmsg2(100, "Failed to convert acl into text on file \"%s\": %ld\n",
+                  jcr->last_fname, type.u64);
+            goto bail_out;
+         }
+         break;
+      default:
+         Mmsg1(jcr->errmsg, _("Failed to convert acl into text on file \"%s\"\n"),
+               jcr->last_fname);
+         Dmsg2(100, "Failed to convert acl into text on file \"%s\": %ld\n",
+               jcr->last_fname, type.u64);
+         goto bail_out;
+      }
+   }
+
+   jcr->acl_data->content_length = strlen(jcr->acl_data->content) + 1;
+   switch (type.u64) {
+   case ACL_AIXC:
+      retval = send_acl_stream(jcr, STREAM_ACL_AIX_AIXC);
+   case ACL_NFS4:
+      retval = send_acl_stream(jcr, STREAM_ACL_AIX_NFS4);
+   }
+
+bail_out:
+   free_pool_memory(aclbuf);
+
+   return retval;
+}
+
+static bacl_exit_code aix_parse_acl_streams(JCR *jcr, int stream)
+{
+   int cnt;
+   berrno be;
+   acl_type_t type;
+   size_t aclsize;
+   bacl_exit_code retval = bacl_exit_error;
+   POOLMEM *aclbuf = get_pool_memory(PM_MESSAGE);
+
+   switch (stream) {
+   case STREAM_ACL_AIX_TEXT:
+      /**
+       * Handle the old stream using the old system call for now.
+       */
+      if (acl_put(jcr->last_fname, jcr->acl_data->content, 0) != 0) {
+         retval = bacl_exit_error;
+         goto bail_out;
+      }
+      retval = bacl_exit_ok;
+      goto bail_out;
+   case STREAM_ACL_AIX_AIXC:
+      type.u64 = ACL_AIXC;
+      break;
+   case STREAM_ACL_AIX_NFS4:
+      type.u64 = ACL_NFS4;
+      break;
+   default:
+      goto bail_out;
+   } /* end switch (stream) */
+
+   /**
+    * Set the acl buffer to an initial size. For now we set it
+    * to the same size as the ASCII representation.
+    */
+   aclbuf = check_pool_memory_size(aclbuf, jcr->acl_data->content_length);
+   aclsize = jcr->acl_data->content_length;
+   if (aclx_scanStr(jcr->acl_data->content, aclbuf, &aclsize, type) < 0) {
+      switch (errno) {
+      case ENOSPC:
+         /**
+          * The buffer isn't big enough. The man page doesn't say that aclsize
+          * is updated to the needed size as what is done with aclx_printStr.
+          * So for now we try to increase the buffer a maximum of 3 times
+          * and retry the conversion.
+          */
+         for (cnt = 0; cnt < 3; cnt++) {
+            aclsize = 2 * aclsize;
+            aclbuf = check_pool_memory_size(aclbuf, aclsize);
+
+            if (aclx_scanStr(jcr->acl_data->content, aclbuf, &aclsize, type) == 0) {
+               break;
+            }
+
+            /**
+             * See why we failed this time, ENOSPC retry if max retries not met,
+             * otherwise abort.
+             */
+            switch (errno) {
+            case ENOSPC:
+               continue;
+            default:
+               Mmsg2(jcr->errmsg, _("aclx_scanStr error on file \"%s\": ERR=%s\n"),
+                     jcr->last_fname, be.bstrerror());
+               Dmsg2(100, "aclx_scanStr error file=%s ERR=%s\n",
+                     jcr->last_fname, be.bstrerror());
+               goto bail_out;
+            }
+         }
+         break;
+      default:
+         Mmsg2(jcr->errmsg, _("aclx_scanStr error on file \"%s\": ERR=%s\n"),
+               jcr->last_fname, be.bstrerror());
+         Dmsg2(100, "aclx_scanStr error file=%s ERR=%s\n",
+               jcr->last_fname, be.bstrerror());
+      }
+   }
+
+   if (aclx_put(jcr->last_fname, SET_ACL, type, aclbuf, aclsize, 0) < 0) {
+      switch (errno) {
+      case ENOENT:
+         retval = bacl_exit_ok;
+         goto bail_out;
+      default:
+         Mmsg2(jcr->errmsg, _("aclx_put error on file \"%s\": ERR=%s\n"),
+               jcr->last_fname, be.bstrerror());
+         Dmsg2(100, "aclx_put error file=%s ERR=%s\n",
+               jcr->last_fname, be.bstrerror());
+         goto bail_out;
+      }
+   }
+
+   retval = bacl_exit_ok;
+
+bail_out:
+   free_pool_memory(aclbuf);
+
+   return retval;
+}
+
+#else /* HAVE_EXTENDED_ACL */
+
 #include <sys/access.h>
 
 /**
@@ -153,6 +393,7 @@ static bacl_exit_code aix_parse_acl_streams(JCR *jcr, int stream)
    }
    return bacl_exit_ok;
 }
+#endif /* HAVE_EXTENDED_ACL */
 
 /**
  * For this OS setup the build and parse function pointer to the OS specific functions.
@@ -1248,77 +1489,7 @@ static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = solaris_pa
 #endif /* HAVE_SUN_OS */
 #endif /* HAVE_ACL */
 
-#if defined(HAVE_AFS_ACL)
-
-#include <afs/stds.h>
-#include <afs/afs.h>
-#include <afs/auth.h>
-#include <afs/venus.h>
-#include <afs/prs_fs.h>
-
-/**
- * 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];
-   berrno be;
-
-   /**
-    * 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) {
-      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->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
-   return send_acl_stream(jcr, STREAM_ACL_AFS_TEXT);
-}
-
-static bacl_exit_code afs_parse_acl_stream(JCR *jcr, int stream)
-{
-   int error;
-   struct ViceIoctl vip;
-   berrno be;
-
-   vip.in = jcr->acl_data->content;
-   vip.in_size = jcr->acl_data->content_length;
-   vip.out = NULL;
-   vip.out_size = 0;
-
-   if ((error = pioctl(jcr->last_fname, VIOCSETAL, &vip, 0)) < 0) {
-      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.
  */
 
@@ -1333,41 +1504,20 @@ bacl_exit_code build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
     * it with the current st_dev in the last stat performed on
     * the file we are currently storing.
     */
-   if (jcr->acl_data->current_dev != ff_pkt->statp->st_dev) {
+   if (jcr->acl_data->current_dev != ff_pkt->statp.st_dev) {
       /**
        * 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_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;
+      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
@@ -1392,10 +1542,6 @@ bacl_exit_code parse_acl_streams(JCR *jcr, int stream)
    unsigned int cnt;
 
    switch (stream) {
-#if defined(HAVE_AFS_ACL)
-   case STREAM_ACL_AFS_TEXT:
-      return afs_parse_acl_stream(jcr, stream);
-#endif
 #if defined(HAVE_ACL)
    case STREAM_UNIX_ACCESS_ACL:
    case STREAM_UNIX_DEFAULT_ACL: