2007-06-09 Havoc Pennington <hp@redhat.com>
authorHavoc Pennington <hp@redhat.com>
Sun, 10 Jun 2007 04:54:45 +0000 (04:54 +0000)
committerHavoc Pennington <hp@redhat.com>
Sun, 10 Jun 2007 04:54:45 +0000 (04:54 +0000)
* dbus/dbus-string.c (_dbus_string_pop_line): fix this not to
think an empty line is the end of the file.
Also, fix some whitespace.

* dbus/dbus-string-util.c: add more tests for
_dbus_string_pop_line() revealing that it thinks an empty line is
the end of the file, which broke dbus-auth-script.c so
it didn't really run the scripts

* dbus/dbus-auth.c: add ANONYMOUS mechanism

* dbus/dbus-auth-script.c (_dbus_auth_script_run): fix to detect
an empty/no-op auth script; add commands to check that we have or
don't have the expected credentials

ChangeLog
dbus/dbus-auth-script.c
dbus/dbus-auth.c
dbus/dbus-string-util.c
dbus/dbus-string.c
test/data/auth/anonymous-client-successful.auth-script [new file with mode: 0644]
test/data/auth/anonymous-server-successful.auth-script [new file with mode: 0644]
test/data/auth/external-failed.auth-script
test/data/auth/external-root.auth-script
test/data/auth/external-silly.auth-script
test/data/auth/external-successful.auth-script

index c7d2479..5806aee 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,22 @@
 2007-06-09  Havoc Pennington  <hp@redhat.com>
 
+       * dbus/dbus-string.c (_dbus_string_pop_line): fix this not to
+       think an empty line is the end of the file.
+       Also, fix some whitespace.
+
+       * dbus/dbus-string-util.c: add more tests for
+       _dbus_string_pop_line() revealing that it thinks an empty line is
+       the end of the file, which broke dbus-auth-script.c so 
+       it didn't really run the scripts
+
+       * dbus/dbus-auth.c: add ANONYMOUS mechanism
+
+       * dbus/dbus-auth-script.c (_dbus_auth_script_run): fix to detect
+       an empty/no-op auth script; add commands to check that we have or
+       don't have the expected credentials     
+
+2007-06-09  Havoc Pennington  <hp@redhat.com>
+
        * bus/policy.c (bus_policy_create_client_policy): gracefully
        continue if the connection has no unix user - just don't apply 
        any unix user dependent rules.
index 5aa17d4..dd864ca 100644 (file)
@@ -218,10 +218,8 @@ auth_set_unix_credentials(DBusAuth  *auth,
 
   credentials = _dbus_credentials_new ();
   if (credentials == NULL)
-    {
-      _dbus_warn ("no memory\n");
-      return;
-    }
+    _dbus_assert_not_reached ("no memory");
+
   if (uid != DBUS_UID_UNSET)
     _dbus_credentials_add_unix_uid (credentials, uid);
   if (pid != DBUS_PID_UNSET)
@@ -288,11 +286,14 @@ _dbus_auth_script_run (const DBusString *filename)
 
   state = DBUS_AUTH_STATE_NEED_DISCONNECT;
   line_no = 0;
+
  next_iteration:
   while (_dbus_string_pop_line (&file, &line))
     {      
       line_no += 1;
 
+      /* _dbus_warn ("%s\n", _dbus_string_get_const_data (&line)); */
+      
       _dbus_string_delete_leading_blanks (&line);
 
       if (auth != NULL)
@@ -659,6 +660,30 @@ _dbus_auth_script_run (const DBusString *filename)
             }
         }
       else if (_dbus_string_starts_with_c_str (&line,
+                                               "EXPECT_HAVE_NO_CREDENTIALS"))
+        {
+          DBusCredentials *authorized_identity;
+          
+          authorized_identity = _dbus_auth_get_identity (auth);
+          if (!_dbus_credentials_are_empty (authorized_identity))
+            {
+              _dbus_warn ("Expected anonymous login or failed login, but some credentials were authorized\n");
+              goto out;
+            }
+        }
+      else if (_dbus_string_starts_with_c_str (&line,
+                                               "EXPECT_HAVE_SOME_CREDENTIALS"))
+        {
+          DBusCredentials *authorized_identity;
+          
+          authorized_identity = _dbus_auth_get_identity (auth);
+          if (_dbus_credentials_are_empty (authorized_identity))
+            {
+              _dbus_warn ("Expected to have some credentials, but we don't\n");
+              goto out;
+            }
+        }
+      else if (_dbus_string_starts_with_c_str (&line,
                                                "EXPECT"))
         {
           DBusString expected;
@@ -708,8 +733,12 @@ _dbus_auth_script_run (const DBusString *filename)
       }
     }
 
-  if (auth != NULL &&
-      state == DBUS_AUTH_STATE_AUTHENTICATED)
+  if (auth == NULL)
+    {
+      _dbus_warn ("Auth script is bogus, did not even have CLIENT or SERVER\n");
+      goto out;
+    }
+  else if (state == DBUS_AUTH_STATE_AUTHENTICATED)
     {
       const DBusString *unused;
 
index b1d57a4..657f8d3 100644 (file)
@@ -424,6 +424,10 @@ shutdown_mech (DBusAuth *auth)
     }
 }
 
+/*
+ * DBUS_COOKIE_SHA1 mechanism
+ */
+
 /* Returns TRUE but with an empty string hash if the
  * cookie_id isn't known. As with all this code
  * TRUE just means we had enough memory.
@@ -982,6 +986,10 @@ handle_client_shutdown_cookie_sha1_mech (DBusAuth *auth)
   _dbus_string_set_length (&auth->challenge, 0);
 }
 
+/*
+ * EXTERNAL mechanism
+ */
+
 static dbus_bool_t
 handle_server_data_external_mech (DBusAuth         *auth,
                                   const DBusString *data)
@@ -1051,7 +1059,7 @@ handle_server_data_external_mech (DBusAuth         *auth,
         }
     }
 
-  if (_dbus_credentials_are_empty(auth->desired_identity))
+  if (_dbus_credentials_are_empty (auth->desired_identity))
     {
       _dbus_verbose ("%s: desired user %s is no good\n",
                      DBUS_AUTH_NAME (auth),
@@ -1142,13 +1150,120 @@ handle_client_shutdown_external_mech (DBusAuth *auth)
 
 }
 
+/*
+ * ANONYMOUS mechanism
+ */
+
+static dbus_bool_t
+handle_server_data_anonymous_mech (DBusAuth         *auth,
+                                   const DBusString *data)
+{  
+  if (_dbus_string_get_length (data) > 0)
+    {
+      /* Client is allowed to send "trace" data, the only defined
+       * meaning is that if it contains '@' it is an email address,
+       * and otherwise it is anything else, and it's supposed to be
+       * UTF-8
+       */
+      if (!_dbus_string_validate_utf8 (data, 0, _dbus_string_get_length (data)))
+        {
+          _dbus_verbose ("%s: Received invalid UTF-8 trace data from ANONYMOUS client\n",
+                         DBUS_AUTH_NAME (auth));
+
+          {
+            DBusString plaintext;
+            DBusString encoded;
+            _dbus_string_init_const (&plaintext, "D-Bus " VERSION);
+            _dbus_string_init (&encoded);
+            _dbus_string_hex_encode (&plaintext, 0,
+                                     &encoded,
+                                     0);
+              _dbus_verbose ("%s: try '%s'\n",
+                             DBUS_AUTH_NAME (auth), _dbus_string_get_const_data (&encoded));
+          }
+          return send_rejected (auth);
+        }
+      
+      _dbus_verbose ("%s: ANONYMOUS client sent trace string: '%s'\n",
+                     DBUS_AUTH_NAME (auth),
+                     _dbus_string_get_const_data (data));
+    }
+
+  /* We want to be anonymous (clear in case some other protocol got midway through I guess) */
+  _dbus_credentials_clear (auth->desired_identity);
+
+  /* Anonymous is always allowed */
+  if (!send_ok (auth))
+    return FALSE;
+
+  _dbus_verbose ("%s: authenticated client as anonymous\n",
+                 DBUS_AUTH_NAME (auth));
+
+  return TRUE;
+}
+
+static void
+handle_server_shutdown_anonymous_mech (DBusAuth *auth)
+{
+  
+}
+
+static dbus_bool_t
+handle_client_initial_response_anonymous_mech (DBusAuth         *auth,
+                                               DBusString       *response)
+{
+  /* Our initial response is a "trace" string which must be valid UTF-8
+   * and must be an email address if it contains '@'.
+   * We just send the dbus implementation info, like a user-agent or
+   * something, because... why not. There's nothing guaranteed here
+   * though, we could change it later.
+   */
+  DBusString plaintext;
+
+  if (!_dbus_string_init (&plaintext))
+    return FALSE;
+
+  if (!_dbus_string_append (&plaintext,
+                            "libdbus " VERSION))
+    goto failed;
+
+  if (!_dbus_string_hex_encode (&plaintext, 0,
+                               response,
+                               _dbus_string_get_length (response)))
+    goto failed;
+
+  _dbus_string_free (&plaintext);
+  
+  return TRUE;
+
+ failed:
+  _dbus_string_free (&plaintext);
+  return FALSE;  
+}
+
+static dbus_bool_t
+handle_client_data_anonymous_mech (DBusAuth         *auth,
+                                  const DBusString *data)
+{
+  
+  return TRUE;
+}
+
+static void
+handle_client_shutdown_anonymous_mech (DBusAuth *auth)
+{
+  
+}
+
 /* Put mechanisms here in order of preference.
- * What I eventually want to have is:
+ * Right now we have:
+ *
+ * - EXTERNAL checks socket credentials (or in the future, other info from the OS)
+ * - DBUS_COOKIE_SHA1 uses a cookie in the home directory, like xauth or ICE
+ * - ANONYMOUS checks nothing but doesn't auth the person as a user
  *
- *  - a mechanism that checks UNIX domain socket credentials
- *  - a simple magic cookie mechanism like X11 or ICE
- *  - mechanisms that chain to Cyrus SASL, so we can use anything it
- *    offers such as Kerberos, X509, whatever.
+ * We might ideally add a mechanism to chain to Cyrus SASL so we can
+ * use its mechanisms as well.
  * 
  */
 static const DBusAuthMechanismHandler
@@ -1169,6 +1284,14 @@ all_mechanisms[] = {
     handle_client_data_cookie_sha1_mech,
     NULL, NULL,
     handle_client_shutdown_cookie_sha1_mech },
+  { "ANONYMOUS",
+    handle_server_data_anonymous_mech,
+    NULL, NULL,
+    handle_server_shutdown_anonymous_mech,
+    handle_client_initial_response_anonymous_mech,
+    handle_client_data_anonymous_mech,
+    NULL, NULL,
+    handle_client_shutdown_anonymous_mech },  
   { NULL, NULL }
 };
 
@@ -1881,7 +2004,8 @@ lookup_command_from_name (DBusString *command)
 }
 
 static void
-goto_state (DBusAuth *auth, const DBusAuthStateData *state)
+goto_state (DBusAuth *auth,
+            const DBusAuthStateData *state)
 {
   _dbus_verbose ("%s: going from state %s to state %s\n",
                  DBUS_AUTH_NAME (auth),
index 16a7934..27bd23a 100644 (file)
@@ -705,43 +705,93 @@ _dbus_string_test (void)
   _dbus_string_free (&str);
 
   {                                                                                           
-  int found,found_len;                                                                        
-  _dbus_string_init_const (&str, "012\r\n567\n90");                                           
-                                                                                           
-  if (!_dbus_string_find_eol(&str, 0, &found, &found_len) || found != 3 || found_len != 2)    
-     _dbus_assert_not_reached ("Did not find '\\r\\n'");                                       
-  if (found != 3 || found_len != 2)                                                           
-     _dbus_assert_not_reached ("invalid return values");                                       
-                                                                                           
-  if (!_dbus_string_find_eol(&str, 5, &found, &found_len))                                    
-    _dbus_assert_not_reached ("Did not find '\\n'");                                          
-  if (found != 8 || found_len != 1)                                                           
-    _dbus_assert_not_reached ("invalid return values");                                       
-                                                                                           
-  if (_dbus_string_find_eol(&str, 9, &found, &found_len))                                     
-    _dbus_assert_not_reached ("Found not expected '\\n'");                                    
-  else if (found != 11 || found_len != 0)                                                     
-    _dbus_assert_not_reached ("invalid return values '\\n'");                                 
-                                                                                           
-  _dbus_string_free (&str);                                                                   
-  }                                                                                                                                                                                    
-  
-  return TRUE;
-}
-
-#endif /* DBUS_BUILD_TESTS */
-
-
-
-
-
-
+    int found, found_len;  
 
+    _dbus_string_init_const (&str, "012\r\n567\n90");
+    
+    if (!_dbus_string_find_eol (&str, 0, &found, &found_len) || found != 3 || found_len != 2)
+      _dbus_assert_not_reached ("Did not find '\\r\\n'");                                       
+    if (found != 3 || found_len != 2)                                                           
+      _dbus_assert_not_reached ("invalid return values");                                       
+    
+    if (!_dbus_string_find_eol (&str, 5, &found, &found_len))                                    
+      _dbus_assert_not_reached ("Did not find '\\n'");                                          
+    if (found != 8 || found_len != 1)                                                           
+      _dbus_assert_not_reached ("invalid return values");                                       
+    
+    if (_dbus_string_find_eol (&str, 9, &found, &found_len))                                     
+      _dbus_assert_not_reached ("Found not expected '\\n'");                                    
+    else if (found != 11 || found_len != 0)                                                     
+      _dbus_assert_not_reached ("invalid return values '\\n'");                                 
+
+    found = -1;
+    found_len = -1;
+    _dbus_string_init_const (&str, "");
+    if (_dbus_string_find_eol (&str, 0, &found, &found_len))
+      _dbus_assert_not_reached ("found an eol in an empty string");
+    _dbus_assert (found == 0);
+    _dbus_assert (found_len == 0);
+    
+    found = -1;
+    found_len = -1;
+    _dbus_string_init_const (&str, "foobar");
+    if (_dbus_string_find_eol (&str, 0, &found, &found_len))
+      _dbus_assert_not_reached ("found eol in string that lacks one");
+    _dbus_assert (found == 6);
+    _dbus_assert (found_len == 0);
+
+    found = -1;
+    found_len = -1;
+    _dbus_string_init_const (&str, "foobar\n");
+    if (!_dbus_string_find_eol (&str, 0, &found, &found_len))
+      _dbus_assert_not_reached ("did not find eol in string that has one at end");
+    _dbus_assert (found == 6);
+    _dbus_assert (found_len == 1);
+  }
 
+  {
+    DBusString line;
 
+#define FIRST_LINE "this is a line"
+#define SECOND_LINE "this is a second line"
+    /* third line is empty */
+#define THIRD_LINE ""
+#define FOURTH_LINE "this is a fourth line"
+    
+    if (!_dbus_string_init (&str))
+      _dbus_assert_not_reached ("no memory");
 
+    if (!_dbus_string_append (&str, FIRST_LINE "\n" SECOND_LINE "\r\n" THIRD_LINE "\n" FOURTH_LINE))
+      _dbus_assert_not_reached ("no memory");
+    
+    if (!_dbus_string_init (&line))
+      _dbus_assert_not_reached ("no memory");
+    
+    if (!_dbus_string_pop_line (&str, &line))
+      _dbus_assert_not_reached ("failed to pop first line");
 
+    _dbus_assert (_dbus_string_equal_c_str (&line, FIRST_LINE));
+    
+    if (!_dbus_string_pop_line (&str, &line))
+      _dbus_assert_not_reached ("failed to pop second line");
 
+    _dbus_assert (_dbus_string_equal_c_str (&line, SECOND_LINE));
+    
+    if (!_dbus_string_pop_line (&str, &line))
+      _dbus_assert_not_reached ("failed to pop third line");
 
+    _dbus_assert (_dbus_string_equal_c_str (&line, THIRD_LINE));
+    
+    if (!_dbus_string_pop_line (&str, &line))
+      _dbus_assert_not_reached ("failed to pop fourth line");
 
+    _dbus_assert (_dbus_string_equal_c_str (&line, FOURTH_LINE));
+    
+    _dbus_string_free (&str);
+    _dbus_string_free (&line);
+  }
+  
+  return TRUE;
+}
 
+#endif /* DBUS_BUILD_TESTS */
index d83a3f3..6177a75 100644 (file)
@@ -1804,9 +1804,9 @@ _dbus_string_find (const DBusString *str,
  */
 dbus_bool_t
 _dbus_string_find_eol (const DBusString *str,
-                   int               start,
-                   int              *found,
-                   int              *found_len)
+                       int               start,
+                       int              *found,
+                       int              *found_len)
 {
   int i;
 
@@ -1843,7 +1843,7 @@ _dbus_string_find_eol (const DBusString *str,
           if (found_len)
             *found_len = 1;
           return TRUE;
-        }      
+        }
       ++i;
     }
 
@@ -2093,17 +2093,33 @@ _dbus_string_pop_line (DBusString *source,
   _dbus_string_set_length (dest, 0);
   
   eol = 0;
+  eol_len = 0;
   if (!_dbus_string_find_eol (source, 0, &eol, &eol_len))
-      eol = _dbus_string_get_length (source);
+    {
+      _dbus_assert (eol == _dbus_string_get_length (source));
+      if (eol == 0)
+        {
+          /* If there's no newline and source has zero length, we're done */
+          return FALSE;
+        }
+      /* otherwise, the last line of the file has no eol characters */
+    }
 
-  if (eol == 0)
-    return FALSE; /* eof */
+  /* remember eol can be 0 if it's an empty line, but eol_len should not be zero also
+   * since find_eol returned TRUE
+   */
   
   if (!_dbus_string_move_len (source, 0, eol + eol_len, dest, 0))
-         return FALSE;
-
+    return FALSE;
+  
   /* remove line ending */
-  return _dbus_string_set_length(dest, eol);
+  if (!_dbus_string_set_length (dest, eol))
+    {
+      _dbus_assert_not_reached ("out of memory when shortening a string");
+      return FALSE;
+    }
+
+  return TRUE;
 }
 
 #ifdef DBUS_BUILD_TESTS
diff --git a/test/data/auth/anonymous-client-successful.auth-script b/test/data/auth/anonymous-client-successful.auth-script
new file mode 100644 (file)
index 0000000..9a1620b
--- /dev/null
@@ -0,0 +1,16 @@
+## this tests that a client can login anonymously
+
+CLIENT
+
+## Reject whatever mechanism the client picks first
+EXPECT_COMMAND AUTH
+SEND 'REJECTED DBUS_TEST_NONEXISTENT_MECH1 ANONYMOUS DBUS_TEST_NONEXISTENT_MECH2'
+
+## And this time we get ANONYMOUS
+
+EXPECT_COMMAND AUTH
+## of course real DBUS_COOKIE_SHA1 would not send this here...
+SEND 'OK 1234deadbeef'
+
+EXPECT_COMMAND BEGIN
+EXPECT_STATE AUTHENTICATED
diff --git a/test/data/auth/anonymous-server-successful.auth-script b/test/data/auth/anonymous-server-successful.auth-script
new file mode 100644 (file)
index 0000000..172ae9d
--- /dev/null
@@ -0,0 +1,13 @@
+## this tests the server side in a successful auth of type ANONYMOUS 
+
+SERVER
+## verify that prior to doing anything, we haven't authed as anyone
+EXPECT_HAVE_NO_CREDENTIALS
+SEND 'AUTH ANONYMOUS 442d42757320312e312e31'
+EXPECT_COMMAND OK
+EXPECT_STATE WAITING_FOR_INPUT
+SEND 'BEGIN'
+EXPECT_STATE AUTHENTICATED
+## verify that we are still anonymous
+EXPECT_HAVE_NO_CREDENTIALS
+
index b11ee9c..7c4e900 100644 (file)
@@ -2,7 +2,10 @@
 
 SERVER
 NO_CREDENTIALS
+## verify that prior to doing anything, we haven't authed as anyone
+EXPECT_HAVE_NO_CREDENTIALS
 SEND 'AUTH EXTERNAL USERID_HEX'
 EXPECT_COMMAND REJECTED
 EXPECT_STATE WAITING_FOR_INPUT
-
+## verify that we still haven't authed as anyone
+EXPECT_HAVE_NO_CREDENTIALS
index b018971..ca5b94a 100644 (file)
@@ -2,7 +2,8 @@
 
 SERVER
 ROOT_CREDENTIALS
-SEND 'AUTH EXTERNAL USERID_HEX'
+## 30 is ASCII '0' in hex
+SEND 'AUTH EXTERNAL 30'
 EXPECT_COMMAND OK
 EXPECT_STATE WAITING_FOR_INPUT
 SEND 'BEGIN'
index 8ac0688..4e18ee8 100644 (file)
@@ -1,8 +1,12 @@
-## this tests we can't auth with silly credentials
+## this tests we can't auth if socket reports silly credentials but we ask for our own uid
 
 SERVER
+## verify that prior to doing anything, we haven't authed as anyone
+EXPECT_HAVE_NO_CREDENTIALS
 SILLY_CREDENTIALS
 SEND 'AUTH EXTERNAL USERID_HEX'
 EXPECT_COMMAND REJECTED
 EXPECT_STATE WAITING_FOR_INPUT
+## verify that we still haven't authed as anyone
+EXPECT_HAVE_NO_CREDENTIALS
 
index 128d329..222938c 100644 (file)
@@ -1,9 +1,12 @@
 ## this tests a successful auth of type EXTERNAL
 
 SERVER
+## verify that prior to doing anything, we haven't authed as anyone
+EXPECT_HAVE_NO_CREDENTIALS
 SEND 'AUTH EXTERNAL USERID_HEX'
 EXPECT_COMMAND OK
 EXPECT_STATE WAITING_FOR_INPUT
 SEND 'BEGIN'
 EXPECT_STATE AUTHENTICATED
-
+## verify that we now have some credentials
+EXPECT_HAVE_SOME_CREDENTIALS