]> gitweb.michael.orlitzky.com - apply-default-acl.git/commitdiff
src/libadacl.c: use asprintf() instead of snprintf() for paths.
authorMichael Orlitzky <michael@orlitzky.com>
Wed, 28 Mar 2018 01:03:01 +0000 (21:03 -0400)
committerMichael Orlitzky <michael@orlitzky.com>
Wed, 28 Mar 2018 01:03:01 +0000 (21:03 -0400)
When constructing a path, there is an ancient problem: how do you
ensure that your path-name buffer is large enough, and what do you do
if it isn't? The existing solution was to use the PATH_MAX constant
from limits.h, which is often a big number, but need not actually be
defined. If a path exceeded PATH_MAX bytes, we would fail.

Now the GNU/BSD extension asprintf() is used instead. The path-name
buffer is constructed on-the-fly to be as large as necessary, and if
allocation fails, an error is returned. This solution is a little
cleaner, and is not too much less portable considering that we only
work on Linux anyway.

configure.ac
src/libadacl.c

index e4742341dc04e8cccf74f4b2addbc9ed9a63629f..80f678dce14fe57f9f1f94e0ff98cbf8115507da 100644 (file)
@@ -20,7 +20,6 @@ AC_HEADER_REQUIRE(acl/libacl.h)
 AC_HEADER_REQUIRE(fcntl.h)
 AC_HEADER_REQUIRE(getopt.h)
 AC_HEADER_REQUIRE(libgen.h)
-AC_HEADER_REQUIRE(limits.h)
 AC_HEADER_REQUIRE(linux/xattr.h)
 AC_HEADER_REQUIRE(sys/acl.h)
 AC_HEADER_REQUIRE(unistd.h)
@@ -44,5 +43,11 @@ AC_CHECK_DECLS([O_PATH],
                [[#define _GNU_SOURCE
                 #include <fcntl.h>]])
 
+# And check for the GNU/BSD extension asprintf(), which lets us avoid
+# praying to the PATH_MAX gods while constructing long paths.
+AC_CHECK_FUNC(asprintf,
+              [],
+              AC_MSG_ERROR(missing required asprintf function))
+
 LT_INIT
 AC_OUTPUT
index ce125db12dc77397574a98e11c683e12d7ed5911..62ab3cc0047dcb2e92dcf3d9b21d86b21fe518b8 100644 (file)
@@ -5,16 +5,17 @@
  *
  */
 
-/* Enables get_current_dir_name() in unistd.h and the O_PATH flag. */
+/* Enables get_current_dir_name() in unistd.h, the O_PATH flag, and
+ * the asprintf() function.
+*/
 #define _GNU_SOURCE
 
 #include <dirent.h>     /* readdir(), etc. */
 #include <errno.h>      /* EINVAL, ELOOP, ENOTDIR, etc. */
 #include <fcntl.h>      /* openat() */
 #include <libgen.h>     /* basename(), dirname() */
-#include <limits.h>     /* PATH_MAX */
 #include <stdbool.h>    /* the "bool" type */
-#include <stdio.h>      /* perror(), snprintf() */
+#include <stdio.h>      /* perror(), asprintf() */
 #include <stdlib.h>     /* free() */
 #include <string.h>     /* strdup() */
 #include <sys/stat.h>   /* fstat() */
@@ -36,7 +37,7 @@
  */
 #define CLOSE_ERROR -1
 #define OPEN_ERROR -1
-#define SNPRINTF_ERROR -1
+#define ASPRINTF_ERROR -1
 #define STAT_ERROR -1
 #define XATTR_ERROR -1
 
@@ -134,11 +135,11 @@ int safe_open(const char* pathname, int flags) {
     return OPEN_ERROR;
   }
 
-  char abspath[PATH_MAX];
-  int snprintf_result = 0;
+  char* abspath = NULL;
+  int asprintf_result = 0;
   if (strchr(pathname, '/') == pathname) {
     /* pathname is already absolute; just copy it. */
-    snprintf_result = snprintf(abspath, PATH_MAX, "%s", pathname);
+    asprintf_result = asprintf(&abspath, "%s", pathname);
   }
   else {
     /* Concatenate the current working directory and pathname into an
@@ -163,14 +164,17 @@ int safe_open(const char* pathname, int flags) {
       free(cwd);
       return OPEN_ERROR;
     }
-    snprintf_result = snprintf(abspath, PATH_MAX, "%s/%s", abs_cwd, pathname);
+    asprintf_result = asprintf(&abspath, "%s/%s", abs_cwd, pathname);
     free(cwd);
   }
-  if (snprintf_result == SNPRINTF_ERROR || snprintf_result > PATH_MAX) {
-    perror("safe_open (snprintf)");
+  if (asprintf_result == ASPRINTF_ERROR) {
+    perror("safe_open (asprintf)");
     return OPEN_ERROR;
   }
 
+  /* Beyond here, asprintf() worked, and we need to free abspath. */
+  int result = OPEN_ERROR;
+
   bool abspath_is_root = (strcmp(abspath, "/") == 0);
   int rootflags = flags | O_DIRECTORY;
   if (!abspath_is_root) {
@@ -180,18 +184,24 @@ int safe_open(const char* pathname, int flags) {
   int rootfd = open("/", rootflags);
   if (rootfd == OPEN_ERROR) {
     perror("safe_open (open)");
-    return OPEN_ERROR;
+    result = OPEN_ERROR;
+    goto cleanup;
   }
 
   if (abspath_is_root) {
-    return rootfd;
+    result = rootfd;
+    goto cleanup;
   }
 
-  int result = safe_open_ex(rootfd, abspath+1, flags);
+  result = safe_open_ex(rootfd, abspath+1, flags);
   if (close(rootfd) == CLOSE_ERROR) {
     perror("safe_open (close)");
-    return OPEN_ERROR;
+    result = OPEN_ERROR;
+    goto cleanup;
   }
+
+ cleanup:
+  free(abspath);
   return result;
 }