summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2009-04-24 04:38:27 +0200
committerLennart Poettering <lennart@poettering.net>2009-05-20 02:09:31 +0200
commitc200e0304d6f53a0fd47f524386b02b27c0c45f6 (patch)
tree2d78c7bb46d1ce81538c7c36cce948f170d933b1
parent89318bbeb4076d8d9de9831d69621fc1411760d3 (diff)
auth: add fd passing negotiation support
This adds two new directives to the auth protocol: NEGOTIATE_UNIX_FD is sent by the client after the authentication was sucessful, i.e. OK was received. AGREE_UNIX_FD is then sent by the server if it can do unix fd passing as well. ERROR is returned when the server cannot or is unwilling to do unix fd passing. This should be compatible with existing D-Bus implementations which will naturally return ERROR on NEGOTIATE_UNIX_FD.
-rw-r--r--bus/dispatch.c5
-rw-r--r--dbus/dbus-auth.c184
-rw-r--r--dbus/dbus-auth.h2
-rw-r--r--dbus/dbus-transport-protected.h3
-rw-r--r--dbus/dbus-transport-socket.c6
-rw-r--r--dbus/dbus-transport.c1
6 files changed, 170 insertions, 31 deletions
diff --git a/bus/dispatch.c b/bus/dispatch.c
index ca9a8433..8ed88dad 100644
--- a/bus/dispatch.c
+++ b/bus/dispatch.c
@@ -4791,6 +4791,11 @@ bus_unix_fds_passing_test(const DBusString *test_data_dir)
if (!_dbus_close(two[0], &error))
_dbus_assert_not_reached("Failed to close pipe #2 ");
+ if (!(dbus_connection_can_send_type(foo, DBUS_TYPE_UNIX_FD)))
+ _dbus_assert_not_reached("Connection cannot do fd passing");
+
+ if (!(dbus_connection_can_send_type(bar, DBUS_TYPE_UNIX_FD)))
+ _dbus_assert_not_reached("Connection cannot do fd passing");
if (!dbus_connection_send (foo, m, NULL))
_dbus_assert_not_reached("Failed to send fds");
diff --git a/dbus/dbus-auth.c b/dbus/dbus-auth.c
index ec7cf312..f1c83ae4 100644
--- a/dbus/dbus-auth.c
+++ b/dbus/dbus-auth.c
@@ -122,7 +122,9 @@ typedef enum {
DBUS_AUTH_COMMAND_REJECTED,
DBUS_AUTH_COMMAND_OK,
DBUS_AUTH_COMMAND_ERROR,
- DBUS_AUTH_COMMAND_UNKNOWN
+ DBUS_AUTH_COMMAND_UNKNOWN,
+ DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD,
+ DBUS_AUTH_COMMAND_AGREE_UNIX_FD
} DBusAuthCommand;
/**
@@ -184,6 +186,9 @@ struct DBusAuth
unsigned int already_got_mechanisms : 1; /**< Client already got mech list */
unsigned int already_asked_for_initial_response : 1; /**< Already sent a blank challenge to get an initial response */
unsigned int buffer_outstanding : 1; /**< Buffer is "checked out" for reading data into */
+
+ unsigned int unix_fd_possible : 1; /**< This side could do unix fd passing */
+ unsigned int unix_fd_negotiated : 1; /**< Unix fd was successfully negotiated */
};
/**
@@ -223,9 +228,10 @@ static dbus_bool_t send_rejected (DBusAuth *auth);
static dbus_bool_t send_error (DBusAuth *auth,
const char *message);
static dbus_bool_t send_ok (DBusAuth *auth);
-static dbus_bool_t send_begin (DBusAuth *auth,
- const DBusString *args_from_ok);
+static dbus_bool_t send_begin (DBusAuth *auth);
static dbus_bool_t send_cancel (DBusAuth *auth);
+static dbus_bool_t send_negotiate_unix_fd (DBusAuth *auth);
+static dbus_bool_t send_agree_unix_fd (DBusAuth *auth);
/**
* Client states
@@ -264,6 +270,9 @@ static dbus_bool_t handle_client_state_waiting_for_ok (DBusAuth *aut
static dbus_bool_t handle_client_state_waiting_for_reject (DBusAuth *auth,
DBusAuthCommand command,
const DBusString *args);
+static dbus_bool_t handle_client_state_waiting_for_agree_unix_fd (DBusAuth *auth,
+ DBusAuthCommand command,
+ const DBusString *args);
static const DBusAuthStateData client_state_need_send_auth = {
"NeedSendAuth", NULL
@@ -277,7 +286,10 @@ static const DBusAuthStateData client_state_waiting_for_ok = {
static const DBusAuthStateData client_state_waiting_for_reject = {
"WaitingForReject", handle_client_state_waiting_for_reject
};
-
+static const DBusAuthStateData client_state_waiting_for_agree_unix_fd = {
+ "WaitingForAgreeUnixFD", handle_client_state_waiting_for_agree_unix_fd
+};
+
/**
* Common terminal states. Terminal states have handler == NULL.
*/
@@ -1522,9 +1534,21 @@ send_ok (DBusAuth *auth)
}
static dbus_bool_t
-send_begin (DBusAuth *auth,
- const DBusString *args_from_ok)
+send_begin (DBusAuth *auth)
{
+
+ if (!_dbus_string_append (&auth->outgoing,
+ "BEGIN\r\n"))
+ return FALSE;
+
+ goto_state (auth, &common_state_authenticated);
+ return TRUE;
+}
+
+static dbus_bool_t
+process_ok(DBusAuth *auth,
+ const DBusString *args_from_ok) {
+
int end_of_hex;
/* "args_from_ok" should be the GUID, whitespace already pulled off the front */
@@ -1549,20 +1573,19 @@ send_begin (DBusAuth *auth,
return TRUE;
}
- if (_dbus_string_copy (args_from_ok, 0, &DBUS_AUTH_CLIENT (auth)->guid_from_server, 0) &&
- _dbus_string_append (&auth->outgoing, "BEGIN\r\n"))
- {
- _dbus_verbose ("Got GUID '%s' from the server\n",
- _dbus_string_get_const_data (& DBUS_AUTH_CLIENT (auth)->guid_from_server));
-
- goto_state (auth, &common_state_authenticated);
- return TRUE;
- }
- else
- {
+ if (!_dbus_string_copy (args_from_ok, 0, &DBUS_AUTH_CLIENT (auth)->guid_from_server, 0)) {
_dbus_string_set_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server, 0);
return FALSE;
- }
+ }
+
+ _dbus_verbose ("Got GUID '%s' from the server\n",
+ _dbus_string_get_const_data (& DBUS_AUTH_CLIENT (auth)->guid_from_server));
+
+ if (auth->unix_fd_possible)
+ return send_negotiate_unix_fd(auth);
+
+ _dbus_verbose("Not negotiating unix fd passing, since not possible\n");
+ return send_begin (auth);
}
static dbus_bool_t
@@ -1622,6 +1645,33 @@ process_data (DBusAuth *auth,
}
static dbus_bool_t
+send_negotiate_unix_fd (DBusAuth *auth)
+{
+ if (!_dbus_string_append (&auth->outgoing,
+ "NEGOTIATE_UNIX_FD\r\n"))
+ return FALSE;
+
+ goto_state (auth, &client_state_waiting_for_agree_unix_fd);
+ return TRUE;
+}
+
+static dbus_bool_t
+send_agree_unix_fd (DBusAuth *auth)
+{
+ _dbus_assert(auth->unix_fd_possible);
+
+ auth->unix_fd_negotiated = TRUE;
+ _dbus_verbose("Agreed to UNIX FD passing\n");
+
+ if (!_dbus_string_append (&auth->outgoing,
+ "AGREE_UNIX_FD\r\n"))
+ return FALSE;
+
+ goto_state (auth, &server_state_waiting_for_begin);
+ return TRUE;
+}
+
+static dbus_bool_t
handle_auth (DBusAuth *auth, const DBusString *args)
{
if (_dbus_string_get_length (args) == 0)
@@ -1712,9 +1762,13 @@ handle_server_state_waiting_for_auth (DBusAuth *auth,
case DBUS_AUTH_COMMAND_ERROR:
return send_rejected (auth);
+ case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD:
+ return send_error (auth, "Need to authenticate first");
+
case DBUS_AUTH_COMMAND_REJECTED:
case DBUS_AUTH_COMMAND_OK:
case DBUS_AUTH_COMMAND_UNKNOWN:
+ case DBUS_AUTH_COMMAND_AGREE_UNIX_FD:
default:
return send_error (auth, "Unknown command");
}
@@ -1741,9 +1795,13 @@ handle_server_state_waiting_for_data (DBusAuth *auth,
goto_state (auth, &common_state_need_disconnect);
return TRUE;
+ case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD:
+ return send_error (auth, "Need to authenticate first");
+
case DBUS_AUTH_COMMAND_REJECTED:
case DBUS_AUTH_COMMAND_OK:
case DBUS_AUTH_COMMAND_UNKNOWN:
+ case DBUS_AUTH_COMMAND_AGREE_UNIX_FD:
default:
return send_error (auth, "Unknown command");
}
@@ -1766,9 +1824,16 @@ handle_server_state_waiting_for_begin (DBusAuth *auth,
goto_state (auth, &common_state_authenticated);
return TRUE;
+ case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD:
+ if (auth->unix_fd_possible)
+ return send_agree_unix_fd(auth);
+ else
+ return send_error(auth, "Unix FD passing not supported, not authenticated or otherwise not possible");
+
case DBUS_AUTH_COMMAND_REJECTED:
case DBUS_AUTH_COMMAND_OK:
case DBUS_AUTH_COMMAND_UNKNOWN:
+ case DBUS_AUTH_COMMAND_AGREE_UNIX_FD:
default:
return send_error (auth, "Unknown command");
@@ -1933,7 +1998,7 @@ handle_client_state_waiting_for_data (DBusAuth *auth,
return process_rejected (auth, args);
case DBUS_AUTH_COMMAND_OK:
- return send_begin (auth, args);
+ return process_ok(auth, args);
case DBUS_AUTH_COMMAND_ERROR:
return send_cancel (auth);
@@ -1942,6 +2007,8 @@ handle_client_state_waiting_for_data (DBusAuth *auth,
case DBUS_AUTH_COMMAND_CANCEL:
case DBUS_AUTH_COMMAND_BEGIN:
case DBUS_AUTH_COMMAND_UNKNOWN:
+ case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD:
+ case DBUS_AUTH_COMMAND_AGREE_UNIX_FD:
default:
return send_error (auth, "Unknown command");
}
@@ -1958,7 +2025,7 @@ handle_client_state_waiting_for_ok (DBusAuth *auth,
return process_rejected (auth, args);
case DBUS_AUTH_COMMAND_OK:
- return send_begin (auth, args);
+ return process_ok(auth, args);
case DBUS_AUTH_COMMAND_DATA:
case DBUS_AUTH_COMMAND_ERROR:
@@ -1968,6 +2035,8 @@ handle_client_state_waiting_for_ok (DBusAuth *auth,
case DBUS_AUTH_COMMAND_CANCEL:
case DBUS_AUTH_COMMAND_BEGIN:
case DBUS_AUTH_COMMAND_UNKNOWN:
+ case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD:
+ case DBUS_AUTH_COMMAND_AGREE_UNIX_FD:
default:
return send_error (auth, "Unknown command");
}
@@ -1990,12 +2059,46 @@ handle_client_state_waiting_for_reject (DBusAuth *auth,
case DBUS_AUTH_COMMAND_OK:
case DBUS_AUTH_COMMAND_ERROR:
case DBUS_AUTH_COMMAND_UNKNOWN:
+ case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD:
+ case DBUS_AUTH_COMMAND_AGREE_UNIX_FD:
default:
goto_state (auth, &common_state_need_disconnect);
return TRUE;
}
}
+static dbus_bool_t
+handle_client_state_waiting_for_agree_unix_fd(DBusAuth *auth,
+ DBusAuthCommand command,
+ const DBusString *args)
+{
+ switch (command)
+ {
+ case DBUS_AUTH_COMMAND_AGREE_UNIX_FD:
+ _dbus_assert(auth->unix_fd_possible);
+ auth->unix_fd_negotiated = TRUE;
+ _dbus_verbose("Sucessfully negotiated UNIX FD passing\n");
+ return send_begin (auth);
+
+ case DBUS_AUTH_COMMAND_ERROR:
+ _dbus_assert(auth->unix_fd_possible);
+ auth->unix_fd_negotiated = FALSE;
+ _dbus_verbose("Failed to negotiate UNIX FD passing\n");
+ return send_begin (auth);
+
+ case DBUS_AUTH_COMMAND_OK:
+ case DBUS_AUTH_COMMAND_DATA:
+ case DBUS_AUTH_COMMAND_REJECTED:
+ case DBUS_AUTH_COMMAND_AUTH:
+ case DBUS_AUTH_COMMAND_CANCEL:
+ case DBUS_AUTH_COMMAND_BEGIN:
+ case DBUS_AUTH_COMMAND_UNKNOWN:
+ case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD:
+ default:
+ return send_error (auth, "Unknown command");
+ }
+}
+
/**
* Mapping from command name to enum
*/
@@ -2005,13 +2108,15 @@ typedef struct {
} DBusAuthCommandName;
static const DBusAuthCommandName auth_command_names[] = {
- { "AUTH", DBUS_AUTH_COMMAND_AUTH },
- { "CANCEL", DBUS_AUTH_COMMAND_CANCEL },
- { "DATA", DBUS_AUTH_COMMAND_DATA },
- { "BEGIN", DBUS_AUTH_COMMAND_BEGIN },
- { "REJECTED", DBUS_AUTH_COMMAND_REJECTED },
- { "OK", DBUS_AUTH_COMMAND_OK },
- { "ERROR", DBUS_AUTH_COMMAND_ERROR }
+ { "AUTH", DBUS_AUTH_COMMAND_AUTH },
+ { "CANCEL", DBUS_AUTH_COMMAND_CANCEL },
+ { "DATA", DBUS_AUTH_COMMAND_DATA },
+ { "BEGIN", DBUS_AUTH_COMMAND_BEGIN },
+ { "REJECTED", DBUS_AUTH_COMMAND_REJECTED },
+ { "OK", DBUS_AUTH_COMMAND_OK },
+ { "ERROR", DBUS_AUTH_COMMAND_ERROR },
+ { "NEGOTIATE_UNIX_FD", DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD },
+ { "AGREE_UNIX_FD", DBUS_AUTH_COMMAND_AGREE_UNIX_FD }
};
static DBusAuthCommand
@@ -2685,6 +2790,31 @@ _dbus_auth_set_context (DBusAuth *auth,
&auth->context, 0, _dbus_string_get_length (context));
}
+/**
+ * Sets whether unix fd passing is potentially on the transport and
+ * hence shall be negotiated.
+ *
+ * @param auth the auth conversation
+ * @param b TRUE when unix fd passing shall be negotiated, otherwise FALSE
+ */
+void
+_dbus_auth_set_unix_fd_possible(DBusAuth *auth, dbus_bool_t b)
+{
+ auth->unix_fd_possible = b;
+}
+
+/**
+ * Queries whether unix fd passing was sucessfully negotiated.
+ *
+ * @param auth the auth conversion
+ * @returns #TRUE when unix fd passing was negotiated.
+ */
+dbus_bool_t
+_dbus_auth_get_unix_fd_negotiated(DBusAuth *auth)
+{
+ return auth->unix_fd_negotiated;
+}
+
/** @} */
/* tests in dbus-auth-util.c */
diff --git a/dbus/dbus-auth.h b/dbus/dbus-auth.h
index 14f8320a..5680df11 100644
--- a/dbus/dbus-auth.h
+++ b/dbus/dbus-auth.h
@@ -75,6 +75,8 @@ dbus_bool_t _dbus_auth_set_context (DBusAuth *auth,
const DBusString *context);
const char* _dbus_auth_get_guid_from_server(DBusAuth *auth);
+void _dbus_auth_set_unix_fd_possible(DBusAuth *auth, dbus_bool_t b);
+dbus_bool_t _dbus_auth_get_unix_fd_negotiated(DBusAuth *auth);
DBUS_END_DECLS
diff --git a/dbus/dbus-transport-protected.h b/dbus/dbus-transport-protected.h
index 023549d0..8c389a6d 100644
--- a/dbus/dbus-transport-protected.h
+++ b/dbus/dbus-transport-protected.h
@@ -144,6 +144,9 @@ DBusTransportOpenResult _dbus_transport_open_platform_specific (DBusAddressEntry
DBusTransport **transport_p,
DBusError *error);
+#define DBUS_TRANSPORT_CAN_SEND_UNIX_FD(x) \
+ _dbus_auth_get_unix_fd_negotiated((x)->auth)
+
DBUS_END_DECLS
#endif /* DBUS_TRANSPORT_PROTECTED_H */
diff --git a/dbus/dbus-transport-socket.c b/dbus/dbus-transport-socket.c
index cc49c851..76699506 100644
--- a/dbus/dbus-transport-socket.c
+++ b/dbus/dbus-transport-socket.c
@@ -594,7 +594,7 @@ do_writing (DBusTransport *transport)
#endif
#ifdef HAVE_UNIX_FD_PASSING
- if (socket_transport->message_bytes_written <= 0 && transport->can_pass_unix_fd)
+ if (socket_transport->message_bytes_written <= 0 && DBUS_TRANSPORT_CAN_SEND_UNIX_FD(transport))
{
/* Send the fds along with the first byte of the message */
const int *unix_fds;
@@ -777,7 +777,7 @@ do_reading (DBusTransport *transport)
&buffer);
#ifdef HAVE_UNIX_FD_PASSING
- if (transport->can_pass_unix_fd)
+ if (DBUS_TRANSPORT_CAN_SEND_UNIX_FD(transport))
{
int *fds, n_fds;
@@ -1244,7 +1244,7 @@ _dbus_transport_new_for_socket (int fd,
goto failed_4;
#ifdef HAVE_UNIX_FD_PASSING
- socket_transport->base.can_pass_unix_fd = _dbus_socket_can_pass_unix_fd(fd);
+ _dbus_auth_set_unix_fd_possible(socket_transport->base.auth, _dbus_socket_can_pass_unix_fd(fd));
#endif
socket_transport->fd = fd;
diff --git a/dbus/dbus-transport.c b/dbus/dbus-transport.c
index 97ee0e9b..7ba01357 100644
--- a/dbus/dbus-transport.c
+++ b/dbus/dbus-transport.c
@@ -184,7 +184,6 @@ _dbus_transport_init_base (DBusTransport *transport,
transport->credentials = creds;
#ifdef HAVE_UNIX_FD_PASSING
- transport->can_pass_unix_fd = FALSE;
transport->unix_fds = NULL;
transport->n_unix_fds = 0;
#endif