Matej Habrnal fa1950
From 0bfb03ea68eb745172feccfc0f01b2ad13ff33bb Mon Sep 17 00:00:00 2001
Matej Habrnal fa1950
From: Jakub Filak <jfilak@redhat.com>
Matej Habrnal fa1950
Date: Fri, 24 Apr 2015 13:48:32 +0200
Matej Habrnal fa1950
Subject: [PATCH] dbus: avoid race-conditions in tests for dum dir availability
Matej Habrnal fa1950
Matej Habrnal fa1950
Florian Weimer <fweimer@redhat.com>
Matej Habrnal fa1950
Matej Habrnal fa1950
    dump_dir_accessible_by_uid() is fundamentally insecure because it
Matej Habrnal fa1950
    opens up a classic time-of-check-time-of-use race between this
Matej Habrnal fa1950
    function and and dd_opendir().
Matej Habrnal fa1950
Matej Habrnal fa1950
Related: #1214745
Matej Habrnal fa1950
Matej Habrnal fa1950
Signed-off-by: Jakub Filak <jfilak@redhat.com>
Matej Habrnal fa1950
---
Matej Habrnal fa1950
 src/dbus/abrt-dbus.c  | 225 +++++++++++++++++++++-----------------------------
Matej Habrnal fa1950
 src/lib/problem_api.c |  21 +++--
Matej Habrnal fa1950
 2 files changed, 109 insertions(+), 137 deletions(-)
Matej Habrnal fa1950
Matej Habrnal fa1950
diff --git a/src/dbus/abrt-dbus.c b/src/dbus/abrt-dbus.c
Matej Habrnal fa1950
index 585fcd7..0f7ac2d 100644
Matej Habrnal fa1950
--- a/src/dbus/abrt-dbus.c
Matej Habrnal fa1950
+++ b/src/dbus/abrt-dbus.c
Matej Habrnal fa1950
@@ -201,6 +201,69 @@ static void return_InvalidProblemDir_error(GDBusMethodInvocation *invocation, co
Matej Habrnal fa1950
     free(msg);
Matej Habrnal fa1950
 }
Matej Habrnal fa1950
 
Matej Habrnal fa1950
+enum {
Matej Habrnal fa1950
+    OPEN_FAIL_NO_REPLY = 1 << 0,
Matej Habrnal fa1950
+    OPEN_AUTH_ASK      = 1 << 1,
Matej Habrnal fa1950
+    OPEN_AUTH_FAIL     = 1 << 2,
Matej Habrnal fa1950
+};
Matej Habrnal fa1950
+
Matej Habrnal fa1950
+static struct dump_dir *open_dump_directory(GDBusMethodInvocation *invocation,
Matej Habrnal fa1950
+    const gchar *caller, uid_t caller_uid, const char *problem_dir, int dd_flags, int flags)
Matej Habrnal fa1950
+{
Matej Habrnal fa1950
+    if (!allowed_problem_dir(problem_dir))
Matej Habrnal fa1950
+    {
Matej Habrnal fa1950
+        log("UID=%d attempted to access not allowed problem directory '%s'",
Matej Habrnal fa1950
+                caller_uid, problem_dir);
Matej Habrnal fa1950
+        if (!(flags & OPEN_FAIL_NO_REPLY))
Matej Habrnal fa1950
+            return_InvalidProblemDir_error(invocation, problem_dir);
Matej Habrnal fa1950
+        return NULL;
Matej Habrnal fa1950
+    }
Matej Habrnal fa1950
+
Matej Habrnal fa1950
+    struct dump_dir *dd = dd_opendir(problem_dir, DD_OPEN_FD_ONLY);
Matej Habrnal fa1950
+    if (dd == NULL)
Matej Habrnal fa1950
+    {
Matej Habrnal fa1950
+        perror_msg("can't open problem directory '%s'", problem_dir);
Matej Habrnal fa1950
+        if (!(flags & OPEN_FAIL_NO_REPLY))
Matej Habrnal fa1950
+            return_InvalidProblemDir_error(invocation, problem_dir);
Matej Habrnal fa1950
+        return NULL;
Matej Habrnal fa1950
+    }
Matej Habrnal fa1950
+
Matej Habrnal fa1950
+    if (!dd_accessible_by_uid(dd, caller_uid))
Matej Habrnal fa1950
+    {
Matej Habrnal fa1950
+        if (errno == ENOTDIR)
Matej Habrnal fa1950
+        {
Matej Habrnal fa1950
+            log_notice("Requested directory does not exist '%s'", problem_dir);
Matej Habrnal fa1950
+            if (!(flags & OPEN_FAIL_NO_REPLY))
Matej Habrnal fa1950
+                return_InvalidProblemDir_error(invocation, problem_dir);
Matej Habrnal fa1950
+            dd_close(dd);
Matej Habrnal fa1950
+            return NULL;
Matej Habrnal fa1950
+        }
Matej Habrnal fa1950
+
Matej Habrnal fa1950
+        if (   !(flags & OPEN_AUTH_ASK)
Matej Habrnal fa1950
+            || polkit_check_authorization_dname(caller, "org.freedesktop.problems.getall") != PolkitYes)
Matej Habrnal fa1950
+        {
Matej Habrnal fa1950
+            log_notice("not authorized");
Matej Habrnal fa1950
+            if (!(flags & OPEN_FAIL_NO_REPLY))
Matej Habrnal fa1950
+                g_dbus_method_invocation_return_dbus_error(invocation,
Matej Habrnal fa1950
+                                              "org.freedesktop.problems.AuthFailure",
Matej Habrnal fa1950
+                                              _("Not Authorized"));
Matej Habrnal fa1950
+            dd_close(dd);
Matej Habrnal fa1950
+            return NULL;
Matej Habrnal fa1950
+        }
Matej Habrnal fa1950
+    }
Matej Habrnal fa1950
+
Matej Habrnal fa1950
+    dd = dd_fdopendir(dd, dd_flags);
Matej Habrnal fa1950
+    if (dd == NULL)
Matej Habrnal fa1950
+    {
Matej Habrnal fa1950
+        log_notice("Can't open the problem '%s' with flags %x0", problem_dir, dd_flags);
Matej Habrnal fa1950
+        if (!(flags & OPEN_FAIL_NO_REPLY))
Matej Habrnal fa1950
+            g_dbus_method_invocation_return_dbus_error(invocation,
Matej Habrnal fa1950
+                                "org.freedesktop.problems.Failure",
Matej Habrnal fa1950
+                                _("Can't open the problem"));
Matej Habrnal fa1950
+    }
Matej Habrnal fa1950
+    return dd;
Matej Habrnal fa1950
+}
Matej Habrnal fa1950
+
Matej Habrnal fa1950
 /*
Matej Habrnal fa1950
  * Checks element's rights and does not open directory if element is protected.
Matej Habrnal fa1950
  * Checks problem's rights and does not open directory if user hasn't got
Matej Habrnal fa1950
@@ -237,35 +300,8 @@ static struct dump_dir *open_directory_for_modification_of_element(
Matej Habrnal fa1950
         }
Matej Habrnal fa1950
     }
Matej Habrnal fa1950
 
Matej Habrnal fa1950
-    if (!dump_dir_accessible_by_uid(problem_id, caller_uid))
Matej Habrnal fa1950
-    {
Matej Habrnal fa1950
-        if (errno == ENOTDIR)
Matej Habrnal fa1950
-        {
Matej Habrnal fa1950
-            log_notice("'%s' is not a valid problem directory", problem_id);
Matej Habrnal fa1950
-            return_InvalidProblemDir_error(invocation, problem_id);
Matej Habrnal fa1950
-        }
Matej Habrnal fa1950
-        else
Matej Habrnal fa1950
-        {
Matej Habrnal fa1950
-            log_notice("UID(%d) is not Authorized to access '%s'", caller_uid, problem_id);
Matej Habrnal fa1950
-            g_dbus_method_invocation_return_dbus_error(invocation,
Matej Habrnal fa1950
-                                "org.freedesktop.problems.AuthFailure",
Matej Habrnal fa1950
-                                _("Not Authorized"));
Matej Habrnal fa1950
-        }
Matej Habrnal fa1950
-
Matej Habrnal fa1950
-        return NULL;
Matej Habrnal fa1950
-    }
Matej Habrnal fa1950
-
Matej Habrnal fa1950
-    struct dump_dir *dd = dd_opendir(problem_id, /* flags : */ 0);
Matej Habrnal fa1950
-    if (!dd)
Matej Habrnal fa1950
-    {   /* This should not happen because of the access check above */
Matej Habrnal fa1950
-        log_notice("Can't access the problem '%s' for modification", problem_id);
Matej Habrnal fa1950
-        g_dbus_method_invocation_return_dbus_error(invocation,
Matej Habrnal fa1950
-                                "org.freedesktop.problems.Failure",
Matej Habrnal fa1950
-                                _("Can't access the problem for modification"));
Matej Habrnal fa1950
-        return NULL;
Matej Habrnal fa1950
-    }
Matej Habrnal fa1950
-
Matej Habrnal fa1950
-    return dd;
Matej Habrnal fa1950
+    return open_dump_directory(invocation, /*caller*/NULL, caller_uid, problem_id, /*Read/Write*/0,
Matej Habrnal fa1950
+                               OPEN_AUTH_FAIL);
Matej Habrnal fa1950
 }
Matej Habrnal fa1950
 
Matej Habrnal fa1950
 
Matej Habrnal fa1950
@@ -421,7 +457,15 @@ static void handle_method_call(GDBusConnection *connection,
Matej Habrnal fa1950
             return;
Matej Habrnal fa1950
         }
Matej Habrnal fa1950
 
Matej Habrnal fa1950
-        int ddstat = dump_dir_stat_for_uid(problem_dir, caller_uid);
Matej Habrnal fa1950
+        struct dump_dir *dd = dd_opendir(problem_dir, DD_OPEN_FD_ONLY);
Matej Habrnal fa1950
+        if (dd == NULL)
Matej Habrnal fa1950
+        {
Matej Habrnal fa1950
+            perror_msg("can't open problem directory '%s'", problem_dir);
Matej Habrnal fa1950
+            return_InvalidProblemDir_error(invocation, problem_dir);
Matej Habrnal fa1950
+            return;
Matej Habrnal fa1950
+        }
Matej Habrnal fa1950
+
Matej Habrnal fa1950
+        int ddstat = dd_stat_for_uid(dd, caller_uid);
Matej Habrnal fa1950
         if (ddstat < 0)
Matej Habrnal fa1950
         {
Matej Habrnal fa1950
             if (errno == ENOTDIR)
Matej Habrnal fa1950
@@ -435,6 +479,7 @@ static void handle_method_call(GDBusConnection *connection,
Matej Habrnal fa1950
 
Matej Habrnal fa1950
             return_InvalidProblemDir_error(invocation, problem_dir);
Matej Habrnal fa1950
 
Matej Habrnal fa1950
+            dd_close(dd);
Matej Habrnal fa1950
             return;
Matej Habrnal fa1950
         }
Matej Habrnal fa1950
 
Matej Habrnal fa1950
@@ -442,6 +487,7 @@ static void handle_method_call(GDBusConnection *connection,
Matej Habrnal fa1950
         {   //caller seems to be in group with access to this dir, so no action needed
Matej Habrnal fa1950
             log_notice("caller has access to the requested directory %s", problem_dir);
Matej Habrnal fa1950
             g_dbus_method_invocation_return_value(invocation, NULL);
Matej Habrnal fa1950
+            dd_close(dd);
Matej Habrnal fa1950
             return;
Matej Habrnal fa1950
         }
Matej Habrnal fa1950
 
Matej Habrnal fa1950
@@ -452,10 +498,11 @@ static void handle_method_call(GDBusConnection *connection,
Matej Habrnal fa1950
             g_dbus_method_invocation_return_dbus_error(invocation,
Matej Habrnal fa1950
                                               "org.freedesktop.problems.AuthFailure",
Matej Habrnal fa1950
                                               _("Not Authorized"));
Matej Habrnal fa1950
+            dd_close(dd);
Matej Habrnal fa1950
             return;
Matej Habrnal fa1950
         }
Matej Habrnal fa1950
 
Matej Habrnal fa1950
-        struct dump_dir *dd = dd_opendir(problem_dir, DD_OPEN_READONLY | DD_FAIL_QUIETLY_EACCES);
Matej Habrnal fa1950
+        dd = dd_fdopendir(dd, DD_OPEN_READONLY | DD_FAIL_QUIETLY_EACCES);
Matej Habrnal fa1950
         if (!dd)
Matej Habrnal fa1950
         {
Matej Habrnal fa1950
             return_InvalidProblemDir_error(invocation, problem_dir);
Matej Habrnal fa1950
@@ -483,37 +530,10 @@ static void handle_method_call(GDBusConnection *connection,
Matej Habrnal fa1950
         g_variant_get_child(parameters, 0, "&s", &problem_dir);
Matej Habrnal fa1950
         log_notice("problem_dir:'%s'", problem_dir);
Matej Habrnal fa1950
 
Matej Habrnal fa1950
-        if (!allowed_problem_dir(problem_dir))
Matej Habrnal fa1950
-        {
Matej Habrnal fa1950
-            return_InvalidProblemDir_error(invocation, problem_dir);
Matej Habrnal fa1950
-            return;
Matej Habrnal fa1950
-        }
Matej Habrnal fa1950
-
Matej Habrnal fa1950
-        if (!dump_dir_accessible_by_uid(problem_dir, caller_uid))
Matej Habrnal fa1950
-        {
Matej Habrnal fa1950
-            if (errno == ENOTDIR)
Matej Habrnal fa1950
-            {
Matej Habrnal fa1950
-                log_notice("Requested directory does not exist '%s'", problem_dir);
Matej Habrnal fa1950
-                return_InvalidProblemDir_error(invocation, problem_dir);
Matej Habrnal fa1950
-                return;
Matej Habrnal fa1950
-            }
Matej Habrnal fa1950
-
Matej Habrnal fa1950
-            if (polkit_check_authorization_dname(caller, "org.freedesktop.problems.getall") != PolkitYes)
Matej Habrnal fa1950
-            {
Matej Habrnal fa1950
-                log_notice("not authorized");
Matej Habrnal fa1950
-                g_dbus_method_invocation_return_dbus_error(invocation,
Matej Habrnal fa1950
-                                                  "org.freedesktop.problems.AuthFailure",
Matej Habrnal fa1950
-                                                  _("Not Authorized"));
Matej Habrnal fa1950
-                return;
Matej Habrnal fa1950
-            }
Matej Habrnal fa1950
-        }
Matej Habrnal fa1950
-
Matej Habrnal fa1950
-        struct dump_dir *dd = dd_opendir(problem_dir, DD_OPEN_READONLY | DD_FAIL_QUIETLY_EACCES);
Matej Habrnal fa1950
+        struct dump_dir *dd = open_dump_directory(invocation, caller, caller_uid,
Matej Habrnal fa1950
+                problem_dir, DD_OPEN_READONLY | DD_FAIL_QUIETLY_EACCES , OPEN_AUTH_ASK);
Matej Habrnal fa1950
         if (!dd)
Matej Habrnal fa1950
-        {
Matej Habrnal fa1950
-            return_InvalidProblemDir_error(invocation, problem_dir);
Matej Habrnal fa1950
             return;
Matej Habrnal fa1950
-        }
Matej Habrnal fa1950
 
Matej Habrnal fa1950
 	/* Get 2nd param - vector of element names */
Matej Habrnal fa1950
         GVariant *array = g_variant_get_child_value(parameters, 1);
Matej Habrnal fa1950
@@ -560,32 +580,10 @@ static void handle_method_call(GDBusConnection *connection,
Matej Habrnal fa1950
 
Matej Habrnal fa1950
         g_variant_get(parameters, "(&s)", &problem_id);
Matej Habrnal fa1950
 
Matej Habrnal fa1950
-        if (!allowed_problem_dir(problem_id))
Matej Habrnal fa1950
-        {
Matej Habrnal fa1950
-            return_InvalidProblemDir_error(invocation, problem_id);
Matej Habrnal fa1950
-            return;
Matej Habrnal fa1950
-        }
Matej Habrnal fa1950
-
Matej Habrnal fa1950
-        int ddstat = dump_dir_stat_for_uid(problem_id, caller_uid);
Matej Habrnal fa1950
-        if ((ddstat & DD_STAT_ACCESSIBLE_BY_UID) == 0 &&
Matej Habrnal fa1950
-                polkit_check_authorization_dname(caller, "org.freedesktop.problems.getall") != PolkitYes)
Matej Habrnal fa1950
-        {
Matej Habrnal fa1950
-            log_notice("Unauthorized access : '%s'", problem_id);
Matej Habrnal fa1950
-            g_dbus_method_invocation_return_dbus_error(invocation,
Matej Habrnal fa1950
-                                              "org.freedesktop.problems.AuthFailure",
Matej Habrnal fa1950
-                                              _("Not Authorized"));
Matej Habrnal fa1950
-            return;
Matej Habrnal fa1950
-        }
Matej Habrnal fa1950
-
Matej Habrnal fa1950
-        struct dump_dir *dd = dd_opendir(problem_id, DD_OPEN_READONLY);
Matej Habrnal fa1950
-        if (dd == NULL)
Matej Habrnal fa1950
-        {
Matej Habrnal fa1950
-            log_notice("Can't access the problem '%s' for reading", problem_id);
Matej Habrnal fa1950
-            g_dbus_method_invocation_return_dbus_error(invocation,
Matej Habrnal fa1950
-                                    "org.freedesktop.problems.Failure",
Matej Habrnal fa1950
-                                    _("Can't access the problem for reading"));
Matej Habrnal fa1950
+        struct dump_dir *dd = open_dump_directory(invocation, caller, caller_uid,
Matej Habrnal fa1950
+                    problem_id, DD_OPEN_READONLY, OPEN_AUTH_ASK);
Matej Habrnal fa1950
+        if (!dd)
Matej Habrnal fa1950
             return;
Matej Habrnal fa1950
-        }
Matej Habrnal fa1950
 
Matej Habrnal fa1950
         problem_data_t *pd = create_problem_data_from_dump_dir(dd);
Matej Habrnal fa1950
         dd_close(dd);
Matej Habrnal fa1950
@@ -629,12 +627,6 @@ static void handle_method_call(GDBusConnection *connection,
Matej Habrnal fa1950
 
Matej Habrnal fa1950
         g_variant_get(parameters, "(&s&s&s)", &problem_id, &element, &value);
Matej Habrnal fa1950
 
Matej Habrnal fa1950
-        if (!allowed_problem_dir(problem_id))
Matej Habrnal fa1950
-        {
Matej Habrnal fa1950
-            return_InvalidProblemDir_error(invocation, problem_id);
Matej Habrnal fa1950
-            return;
Matej Habrnal fa1950
-        }
Matej Habrnal fa1950
-
Matej Habrnal fa1950
         if (element == NULL || element[0] == '\0' || strlen(element) > 64)
Matej Habrnal fa1950
         {
Matej Habrnal fa1950
             log_notice("'%s' is not a valid element name of '%s'", element, problem_id);
Matej Habrnal fa1950
@@ -694,12 +686,6 @@ static void handle_method_call(GDBusConnection *connection,
Matej Habrnal fa1950
 
Matej Habrnal fa1950
         g_variant_get(parameters, "(&s&s)", &problem_id, &element);
Matej Habrnal fa1950
 
Matej Habrnal fa1950
-        if (!allowed_problem_dir(problem_id))
Matej Habrnal fa1950
-        {
Matej Habrnal fa1950
-            return_InvalidProblemDir_error(invocation, problem_id);
Matej Habrnal fa1950
-            return;
Matej Habrnal fa1950
-        }
Matej Habrnal fa1950
-
Matej Habrnal fa1950
         struct dump_dir *dd = open_directory_for_modification_of_element(
Matej Habrnal fa1950
                                     invocation, caller_uid, problem_id, element);
Matej Habrnal fa1950
         if (!dd)
Matej Habrnal fa1950
@@ -732,33 +718,10 @@ static void handle_method_call(GDBusConnection *connection,
Matej Habrnal fa1950
 
Matej Habrnal fa1950
         g_variant_get(parameters, "(&s&s)", &problem_id, &element);
Matej Habrnal fa1950
 
Matej Habrnal fa1950
-        if (!allowed_problem_dir(problem_id))
Matej Habrnal fa1950
-        {
Matej Habrnal fa1950
-            return_InvalidProblemDir_error(invocation, problem_id);
Matej Habrnal fa1950
-            return;
Matej Habrnal fa1950
-        }
Matej Habrnal fa1950
-
Matej Habrnal fa1950
-        struct dump_dir *dd = dd_opendir(problem_id, DD_OPEN_READONLY);
Matej Habrnal fa1950
+        struct dump_dir *dd = open_dump_directory(invocation, caller, caller_uid,
Matej Habrnal fa1950
+                problem_id, DD_OPEN_READONLY, OPEN_AUTH_ASK);
Matej Habrnal fa1950
         if (!dd)
Matej Habrnal fa1950
-        {
Matej Habrnal fa1950
-            log_notice("Can't access the problem '%s'", problem_id);
Matej Habrnal fa1950
-            g_dbus_method_invocation_return_dbus_error(invocation,
Matej Habrnal fa1950
-                                    "org.freedesktop.problems.Failure",
Matej Habrnal fa1950
-                                    _("Can't access the problem"));
Matej Habrnal fa1950
-            return;
Matej Habrnal fa1950
-        }
Matej Habrnal fa1950
-
Matej Habrnal fa1950
-        int ddstat = dump_dir_stat_for_uid(problem_id, caller_uid);
Matej Habrnal fa1950
-        if ((ddstat & DD_STAT_ACCESSIBLE_BY_UID) == 0 &&
Matej Habrnal fa1950
-                polkit_check_authorization_dname(caller, "org.freedesktop.problems.getall") != PolkitYes)
Matej Habrnal fa1950
-        {
Matej Habrnal fa1950
-            dd_close(dd);
Matej Habrnal fa1950
-            log_notice("Unauthorized access : '%s'", problem_id);
Matej Habrnal fa1950
-            g_dbus_method_invocation_return_dbus_error(invocation,
Matej Habrnal fa1950
-                                              "org.freedesktop.problems.AuthFailure",
Matej Habrnal fa1950
-                                              _("Not Authorized"));
Matej Habrnal fa1950
             return;
Matej Habrnal fa1950
-        }
Matej Habrnal fa1950
 
Matej Habrnal fa1950
         int ret = dd_exist(dd, element);
Matej Habrnal fa1950
         dd_close(dd);
Matej Habrnal fa1950
@@ -793,20 +756,18 @@ static void handle_method_call(GDBusConnection *connection,
Matej Habrnal fa1950
         for (GList *l = problem_dirs; l; l = l->next)
Matej Habrnal fa1950
         {
Matej Habrnal fa1950
             const char *dir_name = (const char*)l->data;
Matej Habrnal fa1950
-            if (!dump_dir_accessible_by_uid(dir_name, caller_uid))
Matej Habrnal fa1950
+
Matej Habrnal fa1950
+            struct dump_dir *dd = open_dump_directory(invocation, caller, caller_uid,
Matej Habrnal fa1950
+                        dir_name, /*Read/Write*/0, OPEN_FAIL_NO_REPLY | OPEN_AUTH_ASK);
Matej Habrnal fa1950
+
Matej Habrnal fa1950
+            if (dd)
Matej Habrnal fa1950
             {
Matej Habrnal fa1950
-                if (errno == ENOTDIR)
Matej Habrnal fa1950
+                if (dd_delete(dd) != 0)
Matej Habrnal fa1950
                 {
Matej Habrnal fa1950
-                    log_notice("Requested directory does not exist '%s'", dir_name);
Matej Habrnal fa1950
-                    continue;
Matej Habrnal fa1950
-                }
Matej Habrnal fa1950
-
Matej Habrnal fa1950
-                if (polkit_check_authorization_dname(caller, "org.freedesktop.problems.getall") != PolkitYes)
Matej Habrnal fa1950
-                { // if user didn't provide correct credentials, just move to the next dir
Matej Habrnal fa1950
-                    continue;
Matej Habrnal fa1950
+                    error_msg("Failed to delete problem directory '%s'", dir_name);
Matej Habrnal fa1950
+                    dd_close(dd);
Matej Habrnal fa1950
                 }
Matej Habrnal fa1950
             }
Matej Habrnal fa1950
-            delete_dump_dir(dir_name);
Matej Habrnal fa1950
         }
Matej Habrnal fa1950
 
Matej Habrnal fa1950
         g_dbus_method_invocation_return_value(invocation, NULL);
Matej Habrnal fa1950
diff --git a/src/lib/problem_api.c b/src/lib/problem_api.c
Matej Habrnal fa1950
index 86222cf..96a49fc 100644
Matej Habrnal fa1950
--- a/src/lib/problem_api.c
Matej Habrnal fa1950
+++ b/src/lib/problem_api.c
Matej Habrnal fa1950
@@ -46,7 +46,17 @@ int for_each_problem_in_dir(const char *path,
Matej Habrnal fa1950
             continue; /* skip "." and ".." */
Matej Habrnal fa1950
 
Matej Habrnal fa1950
         char *full_name = concat_path_file(path, dent->d_name);
Matej Habrnal fa1950
-        if (caller_uid == -1 || dump_dir_accessible_by_uid(full_name, caller_uid))
Matej Habrnal fa1950
+
Matej Habrnal fa1950
+        struct dump_dir *dd = dd_opendir(full_name,   DD_OPEN_FD_ONLY
Matej Habrnal fa1950
+                                                    | DD_FAIL_QUIETLY_ENOENT
Matej Habrnal fa1950
+                                                    | DD_FAIL_QUIETLY_EACCES);
Matej Habrnal fa1950
+        if (dd == NULL)
Matej Habrnal fa1950
+        {
Matej Habrnal fa1950
+            VERB2 perror_msg("can't open problem directory '%s'", full_name);
Matej Habrnal fa1950
+            continue;
Matej Habrnal fa1950
+        }
Matej Habrnal fa1950
+
Matej Habrnal fa1950
+        if (caller_uid == -1 || dd_accessible_by_uid(dd, caller_uid))
Matej Habrnal fa1950
         {
Matej Habrnal fa1950
             /* Silently ignore *any* errors, not only EACCES.
Matej Habrnal fa1950
              * We saw "lock file is locked by process PID" error
Matej Habrnal fa1950
@@ -55,14 +65,15 @@ int for_each_problem_in_dir(const char *path,
Matej Habrnal fa1950
             int sv_logmode = logmode;
Matej Habrnal fa1950
             /* Silently ignore errors only in the silent log level. */
Matej Habrnal fa1950
             logmode = g_verbose == 0 ? 0: sv_logmode;
Matej Habrnal fa1950
-            struct dump_dir *dd = dd_opendir(full_name, DD_OPEN_READONLY | DD_FAIL_QUIETLY_EACCES | DD_DONT_WAIT_FOR_LOCK);
Matej Habrnal fa1950
+            dd = dd_fdopendir(dd, DD_OPEN_READONLY | DD_DONT_WAIT_FOR_LOCK);
Matej Habrnal fa1950
             logmode = sv_logmode;
Matej Habrnal fa1950
             if (dd)
Matej Habrnal fa1950
-            {
Matej Habrnal fa1950
                 brk = callback ? callback(dd, arg) : 0;
Matej Habrnal fa1950
-                dd_close(dd);
Matej Habrnal fa1950
-            }
Matej Habrnal fa1950
         }
Matej Habrnal fa1950
+
Matej Habrnal fa1950
+        if (dd)
Matej Habrnal fa1950
+            dd_close(dd);
Matej Habrnal fa1950
+
Matej Habrnal fa1950
         free(full_name);
Matej Habrnal fa1950
         if (brk)
Matej Habrnal fa1950
             break;
Matej Habrnal fa1950
-- 
Matej Habrnal fa1950
2.1.0
Matej Habrnal fa1950