D-Bus  1.10.12
dbus-nonce.c
00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
00002 /* dbus-nonce.c  Nonce handling functions used by nonce-tcp (internal to D-Bus implementation)
00003  *
00004  * Copyright (C) 2009 Klaralvdalens Datakonsult AB, a KDAB Group company, info@kdab.net
00005  *
00006  * Licensed under the Academic Free License version 2.1
00007  *
00008  * This program is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * This program is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, write to the Free Software
00020  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  *
00022  */
00023 
00024 #include <config.h>
00025 // major sections of this file are modified code from libassuan, (C) FSF
00026 #include "dbus-nonce.h"
00027 #include "dbus-internals.h"
00028 #include "dbus-protocol.h"
00029 #include "dbus-sysdeps.h"
00030 
00031 #include <stdio.h>
00032 
00033 static dbus_bool_t
00034 do_check_nonce (DBusSocket fd, const DBusString *nonce, DBusError *error)
00035 {
00036   DBusString buffer;
00037   DBusString p;
00038   size_t nleft;
00039   dbus_bool_t result;
00040   int n;
00041 
00042   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00043 
00044   nleft = 16;
00045 
00046   if (   !_dbus_string_init (&buffer)
00047       || !_dbus_string_init (&p) ) {
00048         dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00049         _dbus_string_free (&p);
00050         _dbus_string_free (&buffer);
00051         return FALSE;
00052       }
00053 
00054   while (nleft)
00055     {
00056       int saved_errno;
00057 
00058       n = _dbus_read_socket (fd, &p, nleft);
00059       saved_errno = _dbus_save_socket_errno ();
00060 
00061       if (n == -1 && _dbus_get_is_errno_eintr (saved_errno))
00062         ;
00063       else if (n == -1 && _dbus_get_is_errno_eagain_or_ewouldblock (saved_errno))
00064         _dbus_sleep_milliseconds (100);
00065       else if (n==-1)
00066         {
00067           dbus_set_error (error, DBUS_ERROR_IO_ERROR, "Could not read nonce from socket (fd=%d)", fd );
00068           _dbus_string_free (&p);
00069           _dbus_string_free (&buffer);
00070           return FALSE;
00071         }
00072       else if (!n)
00073         {
00074           _dbus_string_free (&p);
00075           _dbus_string_free (&buffer);
00076           dbus_set_error (error, DBUS_ERROR_IO_ERROR, "Could not read nonce from socket (fd=%d)", fd );
00077           return FALSE;
00078         }
00079       else
00080         {
00081           if (!_dbus_string_append_len (&buffer, _dbus_string_get_const_data (&p), n))
00082             {
00083               dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00084               _dbus_string_free (&p);
00085               _dbus_string_free (&buffer);
00086               return FALSE;
00087             }
00088           nleft -= n;
00089         }
00090     }
00091 
00092   result =  _dbus_string_equal_len (&buffer, nonce, 16);
00093   if (!result)
00094     dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, "Nonces do not match, access denied (fd=%d)", fd );
00095 
00096   _dbus_string_free (&p);
00097   _dbus_string_free (&buffer);
00098 
00099   return result;
00100 }
00101 
00110 dbus_bool_t
00111 _dbus_read_nonce (const DBusString *fname, DBusString *nonce, DBusError* error)
00112 {
00113   FILE *fp;
00114   char buffer[17];
00115   size_t nread;
00116 
00117   buffer[sizeof buffer - 1] = '\0';
00118 
00119   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00120 
00121   _dbus_verbose ("reading nonce from file: %s\n", _dbus_string_get_const_data (fname));
00122 
00123 
00124   fp = fopen (_dbus_string_get_const_data (fname), "rb");
00125   if (!fp)
00126     {
00127       dbus_set_error (error,
00128                       _dbus_error_from_system_errno (),
00129                       "Failed to open %s for read: %s",
00130                       _dbus_string_get_const_data (fname),
00131                       _dbus_strerror_from_errno ());
00132       return FALSE;
00133     }
00134 
00135   nread = fread (buffer, 1, sizeof buffer - 1, fp);
00136   fclose (fp);
00137   if (!nread)
00138     {
00139       dbus_set_error (error, DBUS_ERROR_FILE_NOT_FOUND, "Could not read nonce from file %s", _dbus_string_get_const_data (fname));
00140       return FALSE;
00141     }
00142 
00143   if (!_dbus_string_append_len (nonce, buffer, sizeof buffer - 1 ))
00144     {
00145       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00146       return FALSE;
00147     }
00148   return TRUE;
00149 }
00150 
00151 DBusSocket
00152 _dbus_accept_with_noncefile (DBusSocket listen_fd, const DBusNonceFile *noncefile)
00153 {
00154   DBusSocket fd;
00155   DBusString nonce;
00156 
00157   _dbus_assert (noncefile != NULL);
00158   if (!_dbus_string_init (&nonce))
00159     return _dbus_socket_get_invalid ();
00160   //PENDING(kdab): set better errors
00161   if (_dbus_read_nonce (_dbus_noncefile_get_path(noncefile), &nonce, NULL) != TRUE)
00162     return _dbus_socket_get_invalid ();
00163   fd = _dbus_accept (listen_fd);
00164   if (!_dbus_socket_is_valid (fd))
00165     return fd;
00166   if (do_check_nonce(fd, &nonce, NULL) != TRUE) {
00167     _dbus_verbose ("nonce check failed. Closing socket.\n");
00168     _dbus_close_socket(fd, NULL);
00169     return _dbus_socket_get_invalid ();
00170   }
00171 
00172   return fd;
00173 }
00174 
00175 static dbus_bool_t
00176 generate_and_write_nonce (const DBusString *filename, DBusError *error)
00177 {
00178   DBusString nonce;
00179   dbus_bool_t ret;
00180 
00181   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00182 
00183   if (!_dbus_string_init (&nonce))
00184     {
00185       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00186       return FALSE;
00187     }
00188 
00189   if (!_dbus_generate_random_bytes (&nonce, 16, error))
00190     {
00191       _dbus_string_free (&nonce);
00192       return FALSE;
00193     }
00194 
00195   ret = _dbus_string_save_to_file (&nonce, filename, FALSE, error);
00196 
00197   _dbus_string_free (&nonce);
00198 
00199   return ret;
00200 }
00201 
00211 dbus_bool_t
00212 _dbus_send_nonce (DBusSocket        fd,
00213                   const DBusString *noncefile,
00214                   DBusError        *error)
00215 {
00216   dbus_bool_t read_result;
00217   int send_result;
00218   DBusString nonce;
00219 
00220   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00221 
00222   if (_dbus_string_get_length (noncefile) == 0)
00223     return FALSE;
00224 
00225   if (!_dbus_string_init (&nonce))
00226     {
00227       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00228       return FALSE;
00229     }
00230 
00231   read_result = _dbus_read_nonce (noncefile, &nonce, error);
00232   if (!read_result)
00233     {
00234       _DBUS_ASSERT_ERROR_IS_SET (error);
00235       _dbus_string_free (&nonce);
00236       return FALSE;
00237     }
00238   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00239 
00240   send_result = _dbus_write_socket (fd, &nonce, 0, _dbus_string_get_length (&nonce));
00241 
00242   _dbus_string_free (&nonce);
00243 
00244   if (send_result == -1)
00245     {
00246       dbus_set_error (error,
00247                       _dbus_error_from_system_errno (),
00248                       "Failed to send nonce (fd=%d): %s",
00249                       fd, _dbus_strerror_from_errno ());
00250       return FALSE;
00251     }
00252 
00253   return TRUE;
00254 }
00255 
00256 static dbus_bool_t
00257 do_noncefile_create (DBusNonceFile *noncefile,
00258                      DBusError *error,
00259                      dbus_bool_t use_subdir)
00260 {
00261     DBusString randomStr;
00262     const char *tmp;
00263 
00264     _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00265 
00266     _dbus_assert (noncefile);
00267 
00268     if (!_dbus_string_init (&randomStr))
00269       {
00270         dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00271         goto on_error;
00272       }
00273 
00274     if (!_dbus_generate_random_ascii (&randomStr, 8, error))
00275       {
00276         goto on_error;
00277       }
00278 
00279     tmp = _dbus_get_tmpdir ();
00280 
00281     if (!_dbus_string_init (&noncefile->dir)
00282         || tmp == NULL
00283         || !_dbus_string_append (&noncefile->dir, tmp))
00284       {
00285         dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00286         goto on_error;
00287       }
00288     if (use_subdir)
00289       {
00290         if (!_dbus_string_append (&noncefile->dir, "/dbus_nonce-")
00291             || !_dbus_string_append (&noncefile->dir, _dbus_string_get_const_data (&randomStr)) )
00292           {
00293             dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00294             goto on_error;
00295           }
00296         if (!_dbus_string_init (&noncefile->path)
00297             || !_dbus_string_copy (&noncefile->dir, 0, &noncefile->path, 0)
00298             || !_dbus_string_append (&noncefile->path, "/nonce"))
00299           {
00300             dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00301             goto on_error;
00302           }
00303         if (!_dbus_create_directory (&noncefile->dir, error))
00304           {
00305             _DBUS_ASSERT_ERROR_IS_SET (error);
00306             goto on_error;
00307           }
00308         _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00309 
00310       }
00311     else
00312       {
00313         if (!_dbus_string_init (&noncefile->path)
00314             || !_dbus_string_copy (&noncefile->dir, 0, &noncefile->path, 0)
00315             || !_dbus_string_append (&noncefile->path, "/dbus_nonce-")
00316             || !_dbus_string_append (&noncefile->path, _dbus_string_get_const_data (&randomStr)))
00317           {
00318             dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00319             goto on_error;
00320           }
00321 
00322       }
00323 
00324     if (!generate_and_write_nonce (&noncefile->path, error))
00325       {
00326         _DBUS_ASSERT_ERROR_IS_SET (error);
00327         if (use_subdir)
00328           _dbus_delete_directory (&noncefile->dir, NULL); //we ignore possible errors deleting the dir and return the write error instead
00329         goto on_error;
00330       }
00331     _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00332 
00333     _dbus_string_free (&randomStr);
00334 
00335     return TRUE;
00336   on_error:
00337     if (use_subdir)
00338       _dbus_delete_directory (&noncefile->dir, NULL);
00339     _dbus_string_free (&noncefile->dir);
00340     _dbus_string_free (&noncefile->path);
00341     _dbus_string_free (&randomStr);
00342     return FALSE;
00343 }
00344 
00345 #ifdef DBUS_WIN
00346 
00353 dbus_bool_t
00354 _dbus_noncefile_create (DBusNonceFile *noncefile,
00355                         DBusError *error)
00356 {
00357     return do_noncefile_create (noncefile, error, /*use_subdir=*/FALSE);
00358 }
00359 
00367 dbus_bool_t
00368 _dbus_noncefile_delete (DBusNonceFile *noncefile,
00369                         DBusError *error)
00370 {
00371     _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00372 
00373     _dbus_delete_file (&noncefile->path, error);
00374     _dbus_string_free (&noncefile->dir);
00375     _dbus_string_free (&noncefile->path);
00376     return TRUE;
00377 }
00378 
00379 #else
00380 
00388 dbus_bool_t
00389 _dbus_noncefile_create (DBusNonceFile *noncefile,
00390                         DBusError *error)
00391 {
00392     return do_noncefile_create (noncefile, error, /*use_subdir=*/TRUE);
00393 }
00394 
00402 dbus_bool_t
00403 _dbus_noncefile_delete (DBusNonceFile *noncefile,
00404                         DBusError *error)
00405 {
00406     _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00407 
00408     _dbus_delete_directory (&noncefile->dir, error);
00409     _dbus_string_free (&noncefile->dir);
00410     _dbus_string_free (&noncefile->path);
00411     return TRUE;
00412 }
00413 #endif
00414 
00415 
00422 const DBusString*
00423 _dbus_noncefile_get_path (const DBusNonceFile *noncefile)
00424 {
00425     _dbus_assert (noncefile);
00426     return &noncefile->path;
00427 }
00428 
00439 dbus_bool_t
00440 _dbus_noncefile_check_nonce (DBusSocket fd,
00441                              const DBusNonceFile *noncefile,
00442                              DBusError* error)
00443 {
00444     return do_check_nonce (fd, _dbus_noncefile_get_path (noncefile), error);
00445 }
00446 
00447