mirror of
https://gitlab.freedesktop.org/dbus/dbus.git
synced 2026-02-04 04:50:40 +01:00
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
This commit is contained in:
parent
7be5fd95cd
commit
a789b7b38c
11 changed files with 338 additions and 62 deletions
17
ChangeLog
17
ChangeLog
|
|
@ -1,3 +1,20 @@
|
|||
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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
@ -658,6 +659,30 @@ _dbus_auth_script_run (const DBusString *filename)
|
|||
goto out;
|
||||
}
|
||||
}
|
||||
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"))
|
||||
{
|
||||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
138
dbus/dbus-auth.c
138
dbus/dbus-auth.c
|
|
@ -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:
|
||||
*
|
||||
* - 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.
|
||||
* - 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
|
||||
*
|
||||
* 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),
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
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 */
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
16
test/data/auth/anonymous-client-successful.auth-script
Normal file
16
test/data/auth/anonymous-client-successful.auth-script
Normal file
|
|
@ -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
|
||||
13
test/data/auth/anonymous-server-successful.auth-script
Normal file
13
test/data/auth/anonymous-server-successful.auth-script
Normal file
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue