Commit 5e2a99c1 authored by Frank Osterfeld's avatar Frank Osterfeld Committed by Ralf Habacker
Browse files

The current state of the nonce-tcp implementation

Merged and cleaned up patch from my [Frank Osterfeld's] local work
branch.

Cherry-picked from commit e2801eca57b2d9e09afd662ed5ef6fc83be73afc and
edited by tml@iki.fi to make it apply, and fixing whitespace issues.
parent 366ffe44
......@@ -459,8 +459,8 @@ set (DBUS_USER )
if (WIN32)
set (DBUS_SESSION_BUS_DEFAULT_ADDRESS "tcp:host=localhost,port=0")
set (DBUS_SYSTEM_BUS_DEFAULT_ADDRESS "tcp:host=localhost,port=0")
set (DBUS_SESSION_BUS_DEFAULT_ADDRESS "nonce-tcp:host=localhost,port=0")
set (DBUS_SYSTEM_BUS_DEFAULT_ADDRESS "nonce-tcp:host=localhost,port=0")
set (DBUS_SYSTEM_CONFIG_FILE "etc/system.conf")
set (DBUS_SESSION_CONFIG_FILE "etc/session.conf")
# bus-test expects a non empty string
......
......@@ -46,6 +46,7 @@ set (DBUS_LIB_SOURCES
${DBUS_DIR}/dbus-marshal-validate.c
${DBUS_DIR}/dbus-message.c
${DBUS_DIR}/dbus-misc.c
${DBUS_DIR}/dbus-nonce.c
${DBUS_DIR}/dbus-object-tree.c
${DBUS_DIR}/dbus-pending-call.c
${DBUS_DIR}/dbus-resources.c
......
......@@ -138,6 +138,7 @@ DBUS_LIB_SOURCES= \
dbus-message-internal.h \
dbus-message-private.h \
dbus-misc.c \
dbus-nonce.c \
dbus-object-tree.c \
dbus-object-tree.h \
dbus-pending-call.c \
......
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/* dbus-nonce.c Nonce handling functions used by nonce-tcp (internal to D-Bus implementation)
*
* Copyright (C) 2009 Klaralvdalens Datakonsult AB, a KDAB Group company, info@kdab.net
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
// major sections of this file are modified code from libassuan, (C) FSF
#include "dbus-nonce.h"
#include "dbus-internals.h"
#include "dbus-protocol.h"
#include "dbus-sysdeps.h"
#include <stdio.h>
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#ifndef ENOFILE
# define ENOFILE ENOENT
#endif
dbus_bool_t
_dbus_check_nonce (int fd, const DBusString *nonce)
{
DBusString buffer;
DBusString p;
size_t nleft;
dbus_bool_t result;
int n;
nleft = 16;
_dbus_string_init (&buffer);
_dbus_string_init (&p);
//PENDING(kdab) replace errno by DBusError
while (nleft)
{
n = _dbus_read_socket (fd, &p, nleft);
if (n == -1 && _dbus_get_is_errno_eintr())
;
else if (n == -1 && _dbus_get_is_errno_eagain_or_ewouldblock())
_dbus_sleep_milliseconds (100);
else if (n==-1)
{
_dbus_string_free (&p);
_dbus_string_free (&buffer);
return FALSE;
}
else if (!n)
{
_dbus_string_free (&p);
_dbus_string_free (&buffer);
errno = EIO;
return FALSE;
}
else
{
_dbus_string_append_len(&buffer, _dbus_string_get_const_data (&p), n);
nleft -= n;
}
}
result = _dbus_string_equal_len (&buffer, nonce, 16);
if (!result)
errno = EACCES;
_dbus_string_free (&p);
_dbus_string_free (&buffer);
return result;
}
//PENDING(kdab) document
dbus_bool_t
_dbus_read_nonce (const DBusString *fname, DBusString *nonce)
{
//PENDING(kdab) replace errno by DBusError
FILE *fp;
char buffer[17];
buffer[sizeof buffer - 1] = '\0';
size_t nread;
_dbus_verbose ("reading nonce from file: %s\n", _dbus_string_get_const_data (fname));
fp = fopen (_dbus_string_get_const_data (fname), "rb");
if (!fp)
return FALSE;
nread = fread (buffer, 1, sizeof buffer - 1, fp);
fclose (fp);
if (!nread)
{
errno = ENOFILE;
return FALSE;
}
if (!_dbus_string_append_len (nonce, buffer, sizeof buffer - 1 ))
{
errno = ENOMEM;
return FALSE;
}
return TRUE;
}
int
_dbus_accept_with_nonce (int listen_fd, const DBusString *nonce)
{
_dbus_assert (nonce != NULL);
int fd;
fd = _dbus_accept (listen_fd);
if (_dbus_socket_is_invalid (fd))
return fd;
if (_dbus_check_nonce(fd, nonce) != TRUE) {
_dbus_verbose ("nonce check failed. Closing socket.\n");
_dbus_close_socket(fd, NULL);
return -1;
}
return fd;
}
int
_dbus_accept_with_noncefile (int listen_fd, const DBusString *noncefile)
{
_dbus_assert (noncefile != NULL);
DBusString nonce;
_dbus_string_init (&nonce);
//PENDING(kdab): set better errors
if (_dbus_read_nonce (noncefile, &nonce) != TRUE)
return -1;
return _dbus_accept_with_nonce (listen_fd, &nonce);
}
dbus_bool_t
_dbus_generate_noncefilename (DBusString *buf)
{
dbus_bool_t ret;
DBusString randomStr;
ret = _dbus_string_init (&randomStr);
if (!ret)
return FALSE;
ret = _dbus_generate_random_ascii (&randomStr, 8);
if (!ret)
goto oom;
if (!_dbus_string_append (buf, _dbus_get_tmpdir())
|| !_dbus_string_append (buf, DBUS_DIR_SEPARATOR "dbus_nonce-")
|| !_dbus_string_append (buf, _dbus_string_get_const_data (&randomStr)) )
goto oom;
_dbus_string_free (&randomStr);
return TRUE;
oom:
_dbus_string_free (&randomStr);
return FALSE;
}
int
_dbus_generate_and_write_nonce (const DBusString *filename)
{
DBusString nonce;
int ret;
_dbus_string_init (&nonce);
if (!_dbus_generate_random_bytes (&nonce, 16))
return -1;
ret = _dbus_write_to_file (_dbus_string_get_const_data (filename), _dbus_string_get_const_data (&nonce), 16);
_dbus_string_free (&nonce);
return ret;
}
dbus_bool_t
_dbus_send_nonce(int fd, const DBusString *noncefile, DBusError *error)
{
dbus_bool_t read_result;
int send_result;
size_t sendLen;
DBusString nonce;
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
if (_dbus_string_get_length (noncefile) == 0)
return FALSE;
if ( !_dbus_string_init (&nonce) )
{
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
return FALSE;
}
read_result = _dbus_read_nonce (noncefile, &nonce);
if (!read_result)
{
dbus_set_error (error,
_dbus_error_from_errno (errno),
"Could not read nonce from file %s (%s)",
_dbus_string_get_const_data (noncefile), _dbus_strerror(errno));
_dbus_string_free (&nonce);
return FALSE;
}
send_result = _dbus_write_socket (fd, &nonce, 0, _dbus_string_get_length (&nonce));
_dbus_string_free (&nonce);
if (send_result == -1)
{
dbus_set_error (error,
_dbus_error_from_errno (errno),
"Failed to send nonce (fd=%d): %s",
fd, _dbus_strerror(errno));
return FALSE;
}
return TRUE;
}
/** @} end of nonce */
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/* dbus-nonce.h Nonce handling functions used by nonce-tcp (internal to D-Bus implementation)
*
* Copyright (C) 2009 Klaralvdalens Datakonsult AB, a KDAB Group company, info@kdab.net
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef DBUS_NONCE_H
#define DBUS_NONCE_H
#include <dbus/dbus-macros.h>
#include <dbus/dbus-types.h>
#include <dbus/dbus-errors.h>
#include <dbus/dbus-string.h>
DBUS_BEGIN_DECLS
dbus_bool_t _dbus_check_nonce (int fd,
const DBusString *nonce);
dbus_bool_t _dbus_read_nonce (const DBusString *fname,
DBusString *nonce);
int _dbus_accept_with_nonce (int listen_fd,
const DBusString *nonce);
int _dbus_accept_with_noncefile (int listen_fd,
const DBusString *noncefile);
dbus_bool_t _dbus_generate_noncefilename (DBusString *buf);
int _dbus_generate_and_write_nonce (const DBusString *filename);
dbus_bool_t _dbus_send_nonce (int fd,
const DBusString *noncefile,
DBusError *error);
DBUS_END_DECLS
#endif /* DBUS_NONCE_H */
......@@ -51,6 +51,7 @@ struct DBusServerSocket
int *fds; /**< File descriptor or -1 if disconnected. */
DBusWatch **watch; /**< File descriptor watch. */
char *socket_name; /**< Name of domain socket, to unlink if appropriate */
DBusString noncefile; /**< Nonce file used to authenticate clients */
};
static void
......@@ -71,6 +72,11 @@ socket_finalize (DBusServer *server)
dbus_free (socket_server->fds);
dbus_free (socket_server->watch);
dbus_free (socket_server->socket_name);
if (_dbus_string_get_length(&socket_server->noncefile) > 0)
{
_dbus_delete_file(&socket_server->noncefile, NULL);
}
_dbus_string_free (&socket_server->noncefile);
dbus_free (server);
}
......@@ -82,8 +88,10 @@ handle_new_client_fd_and_unlock (DBusServer *server,
DBusConnection *connection;
DBusTransport *transport;
DBusNewConnectionFunction new_connection_function;
DBusServerSocket* socket_server;
void *new_connection_data;
socket_server = (DBusServerSocket*)server;
_dbus_verbose ("Creating new client connection with fd %d\n", client_fd);
HAVE_LOCK_CHECK (server);
......@@ -179,7 +187,7 @@ socket_handle_watch (DBusWatch *watch,
listen_fd = dbus_watch_get_socket (watch);
client_fd = _dbus_accept (listen_fd);
client_fd = _dbus_accept_with_noncefile (listen_fd, &socket_server->noncefile);
if (client_fd < 0)
{
......@@ -257,13 +265,15 @@ static const DBusServerVTable socket_vtable = {
* @param fds list of file descriptors.
* @param n_fds number of file descriptors
* @param address the server's address
* @param noncefile the noncefile to use, NULL if without nonce
* @returns the new server, or #NULL if no memory.
*
*/
DBusServer*
_dbus_server_new_for_socket (int *fds,
int n_fds,
const DBusString *address)
const DBusString *address,
const DBusString *noncefile)
{
DBusServerSocket *socket_server;
DBusServer *server;
......@@ -302,6 +312,12 @@ _dbus_server_new_for_socket (int *fds,
&socket_vtable, address))
goto failed_2;
if (!_dbus_string_init (&socket_server->noncefile))
goto failed_2;
if (noncefile && !_dbus_string_copy (noncefile, 0, &socket_server->noncefile, 0))
goto failed_3;
server = (DBusServer*)socket_server;
SERVER_LOCK (server);
......@@ -326,6 +342,8 @@ _dbus_server_new_for_socket (int *fds,
return (DBusServer*) socket_server;
failed_3:
_dbus_string_free (&socket_server->noncefile);
failed_2:
for (i = 0 ; i < n_fds ; i++)
{
......@@ -368,7 +386,8 @@ _dbus_server_new_for_tcp_socket (const char *host,
const char *bind,
const char *port,
const char *family,
DBusError *error)
DBusError *error,
dbus_bool_t use_nonce)
{
DBusServer *server;
int *listen_fds = NULL;
......@@ -376,6 +395,7 @@ _dbus_server_new_for_tcp_socket (const char *host,
DBusString address;
DBusString host_str;
DBusString port_str;
DBusString noncefile;
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
......@@ -412,7 +432,7 @@ _dbus_server_new_for_tcp_socket (const char *host,
}
_dbus_string_init_const (&host_str, host);
if (!_dbus_string_append (&address, "tcp:host=") ||
if (!_dbus_string_append (&address, use_nonce ? "nonce-tcp:host=" : "tcp:host=") ||
!_dbus_address_append_escaped (&address, &host_str) ||
!_dbus_string_append (&address, ",port=") ||
!_dbus_string_append (&address, _dbus_string_get_const_data(&port_str)))
......@@ -428,7 +448,36 @@ _dbus_server_new_for_tcp_socket (const char *host,
goto failed_2;
}
server = _dbus_server_new_for_socket (listen_fds, nlisten_fds, &address);
if (!_dbus_string_init (&noncefile))
{
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
goto failed_2;
}
if (use_nonce)
{
if (!_dbus_generate_noncefilename (&noncefile))
{
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
goto failed_2;
}
if (_dbus_string_get_length(&noncefile) == 0 ||
!_dbus_string_append (&address, ",noncefile=") ||
!_dbus_address_append_escaped (&address, &noncefile))
{
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
goto failed_2;
}
if (_dbus_generate_and_write_nonce (&noncefile) != 0)
{
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
goto failed_2;
}
}
server = _dbus_server_new_for_socket (listen_fds, nlisten_fds, &address, &noncefile);
if (server == NULL)
{
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
......@@ -445,6 +494,7 @@ _dbus_server_new_for_tcp_socket (const char *host,
for (i = 0 ; i < nlisten_fds ; i++)
_dbus_close_socket (listen_fds[i], NULL);
dbus_free(listen_fds);
_dbus_string_free (&noncefile);
failed_1:
_dbus_string_free (&port_str);
......@@ -457,7 +507,7 @@ _dbus_server_new_for_tcp_socket (const char *host,
/**
* Tries to interpret the address entry for various socket-related
* addresses (well, currently only tcp).
* addresses (well, currently only tcp and nonce-tcp).
*
* Sets error if the result is not OK.
*
......@@ -478,7 +528,7 @@ _dbus_server_listen_socket (DBusAddressEntry *entry,
method = dbus_address_entry_get_method (entry);
if (strcmp (method, "tcp") == 0)
if (strcmp (method, "tcp") == 0 || strcmp (method, "nonce-tcp") == 0)
{
const char *host;
const char *port;
......@@ -491,7 +541,7 @@ _dbus_server_listen_socket (DBusAddressEntry *entry,
family = dbus_address_entry_get_value (entry, "family");
*server_p = _dbus_server_new_for_tcp_socket (host, bind, port,
family, error);
family, error, strcmp (method, "nonce-tcp") == 0 ? TRUE : FALSE);
if (*server_p)
{
......
......@@ -30,12 +30,14 @@ DBUS_BEGIN_DECLS
DBusServer* _dbus_server_new_for_socket (int *fds,
int n_fds,
const DBusString *address);
const DBusString *address,
const DBusString *noncefile);
DBusServer* _dbus_server_new_for_tcp_socket (const char *host,
const char *bind,
const char *port,
const char *family,
DBusError *error);
DBusError *error,
dbus_bool_t use_nonce);
DBusServerListenResult _dbus_server_listen_socket (DBusAddressEntry *entry,
DBusServer **server_p,
DBusError *error);
......
......@@ -208,7 +208,7 @@ _dbus_server_new_for_domain_socket (const char *path,
goto failed_1;
}
server = _dbus_server_new_for_socket (&listen_fd, 1, &address);
server = _dbus_server_new_for_socket (&listen_fd, 1, &address, 0);
if (server == NULL)
{
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
......
......@@ -25,8 +25,6 @@
#include "dbus-internals.h"
#include "dbus-server-win.h"
#include "dbus-server-socket.h"
#include "dbus-connection-internal.h"
#include "dbus-sysdeps-win.h"
/**
* @defgroup DBusServerWin DBusServer implementations for Windows
......@@ -52,13 +50,44 @@ _dbus_server_listen_platform_specific (DBusAddressEntry *entry,
DBusServer **server_p,
DBusError *error)
{
/* don't handle any method yet, return NULL with the error unset,
** for a sample implementation see dbus-server-unix.c
*/
const char *method;
*server_p = NULL;
method = dbus_address_entry_get_method (entry);
if (strcmp (method, "nonce-tcp") == 0)
{
const char *host;
const char *port;
const char *bind;
const char *family;
host = dbus_address_entry_get_value (entry, "host");
bind = dbus_address_entry_get_value (entry, "bind");
port = dbus_address_entry_get_value (entry, "port");
family = dbus_address_entry_get_value (entry, "family");
*server_p = _dbus_server_new_for_tcp_socket (host, bind, port,
family, error, TRUE);
if (*server_p)
{
_DBUS_ASSERT_ERROR_IS_CLEAR(error);
return DBUS_SERVER_LISTEN_OK;
}
else
{
_DBUS_ASSERT_ERROR_IS_SET(error);
return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
}
}
else
{
_DBUS_ASSERT_ERROR_IS_CLEAR(error);
return DBUS_SERVER_LISTEN_NOT_HANDLED;
}
}
/** @} */
......@@ -577,6 +577,11 @@ _dbus_write_socket_two (int fd,
#endif
}
dbus_bool_t
_dbus_socket_is_invalid (int fd)
{
return fd < 0 ? TRUE : FALSE;
}
/**
* Thin wrapper around the read() system call that appends
......@@ -1081,6 +1086,16 @@ _dbus_connect_tcp_socket (const char *host,
const char *port,
const char *family,
DBusError *error)
{
return _dbus_connect_tcp_socket_with_nonce (host, port, family, (const char*)NULL, error);
}
int
_dbus_connect_tcp_socket_with_nonce (const char *host,
const char *port,
const char *family,
const char *noncefile,
DBusError *error)
{
int saved_errno = 0;
int fd = -1, res;
......@@ -1159,12 +1174,24 @@ _dbus_connect_tcp_socket (const char *host,
return -1;
}
if (noncefile != NULL)
{
DBusString noncefileStr;
dbus_bool_t ret;
_dbus_string_init_const (&noncefileStr, noncefile);
ret = _dbus_send_nonce (fd, &noncefileStr, error);
_dbus_string_free (&noncefileStr);
if (!_dbus_set_fd_nonblocking (fd, error))
if (!ret)
{
_dbus_close (fd, NULL);
fd = -1;
return -1;
}