D-Bus 1.4.14
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 (int 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       n = _dbus_read_socket (fd, &p, nleft);
00057       if (n == -1 && _dbus_get_is_errno_eintr())
00058         ;
00059       else if (n == -1 && _dbus_get_is_errno_eagain_or_ewouldblock())
00060         _dbus_sleep_milliseconds (100);
00061       else if (n==-1)
00062         {
00063           dbus_set_error (error, DBUS_ERROR_IO_ERROR, "Could not read nonce from socket (fd=%d)", fd );
00064           _dbus_string_free (&p);
00065           _dbus_string_free (&buffer);
00066           return FALSE;
00067         }
00068       else if (!n)
00069         {
00070           _dbus_string_free (&p);
00071           _dbus_string_free (&buffer);
00072           dbus_set_error (error, DBUS_ERROR_IO_ERROR, "Could not read nonce from socket (fd=%d)", fd );
00073           return FALSE;
00074         }
00075       else
00076         {
00077           _dbus_string_append_len(&buffer, _dbus_string_get_const_data (&p), n);
00078           nleft -= n;
00079         }
00080     }
00081 
00082   result =  _dbus_string_equal_len (&buffer, nonce, 16);
00083   if (!result)
00084     dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, "Nonces do not match, access denied (fd=%d)", fd );
00085 
00086   _dbus_string_free (&p);
00087   _dbus_string_free (&buffer);
00088 
00089   return result;
00090 }
00091 
00100 dbus_bool_t
00101 _dbus_read_nonce (const DBusString *fname, DBusString *nonce, DBusError* error)
00102 {
00103   FILE *fp;
00104   char buffer[17];
00105   size_t nread;
00106 
00107   buffer[sizeof buffer - 1] = '\0';
00108 
00109   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00110 
00111   _dbus_verbose ("reading nonce from file: %s\n", _dbus_string_get_const_data (fname));
00112 
00113 
00114   fp = fopen (_dbus_string_get_const_data (fname), "rb");
00115   if (!fp)
00116     return FALSE;
00117   nread = fread (buffer, 1, sizeof buffer - 1, fp);
00118   fclose (fp);
00119   if (!nread)
00120     {
00121       dbus_set_error (error, DBUS_ERROR_FILE_NOT_FOUND, "Could not read nonce from file %s", _dbus_string_get_const_data (fname));
00122       return FALSE;
00123     }
00124 
00125   if (!_dbus_string_append_len (nonce, buffer, sizeof buffer - 1 ))
00126     {
00127       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00128       return FALSE;
00129     }
00130   return TRUE;
00131 }
00132 
00133 int
00134 _dbus_accept_with_noncefile (int listen_fd, const DBusNonceFile *noncefile)
00135 {
00136   int fd;
00137   DBusString nonce;
00138 
00139   _dbus_assert (noncefile != NULL);
00140   if (!_dbus_string_init (&nonce))
00141     return -1;
00142   //PENDING(kdab): set better errors
00143   if (_dbus_read_nonce (_dbus_noncefile_get_path(noncefile), &nonce, NULL) != TRUE)
00144     return -1;
00145   fd = _dbus_accept (listen_fd);
00146   if (_dbus_socket_is_invalid (fd))
00147     return fd;
00148   if (do_check_nonce(fd, &nonce, NULL) != TRUE) {
00149     _dbus_verbose ("nonce check failed. Closing socket.\n");
00150     _dbus_close_socket(fd, NULL);
00151     return -1;
00152   }
00153 
00154   return fd;
00155 }
00156 
00157 static dbus_bool_t
00158 generate_and_write_nonce (const DBusString *filename, DBusError *error)
00159 {
00160   DBusString nonce;
00161   dbus_bool_t ret;
00162 
00163   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00164 
00165   if (!_dbus_string_init (&nonce))
00166     {
00167       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00168       return FALSE;
00169     }
00170 
00171   if (!_dbus_generate_random_bytes (&nonce, 16))
00172     {
00173       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00174       _dbus_string_free (&nonce);
00175       return FALSE;
00176     }
00177 
00178   ret = _dbus_string_save_to_file (&nonce, filename, FALSE, error);
00179 
00180   _dbus_string_free (&nonce);
00181 
00182   return ret;
00183 }
00184 
00194 dbus_bool_t
00195 _dbus_send_nonce (int fd, const DBusString *noncefile, DBusError *error)
00196 {
00197   dbus_bool_t read_result;
00198   int send_result;
00199   size_t sendLen;
00200   DBusString nonce;
00201 
00202   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00203 
00204   if (_dbus_string_get_length (noncefile) == 0)
00205     return FALSE;
00206 
00207   if (!_dbus_string_init (&nonce))
00208     {
00209       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00210       return FALSE;
00211     }
00212 
00213   read_result = _dbus_read_nonce (noncefile, &nonce, error);
00214   if (!read_result)
00215     {
00216       _DBUS_ASSERT_ERROR_IS_SET (error);
00217       _dbus_string_free (&nonce);
00218       return FALSE;
00219     }
00220   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00221 
00222   send_result = _dbus_write_socket (fd, &nonce, 0, _dbus_string_get_length (&nonce));
00223 
00224   _dbus_string_free (&nonce);
00225 
00226   if (send_result == -1)
00227     {
00228       dbus_set_error (error,
00229                       _dbus_error_from_system_errno (),
00230                       "Failed to send nonce (fd=%d): %s",
00231                       fd, _dbus_strerror_from_errno ());
00232       return FALSE;
00233     }
00234 
00235   return TRUE;
00236 }
00237 
00238 static dbus_bool_t
00239 do_noncefile_create (DBusNonceFile *noncefile,
00240                      DBusError *error,
00241                      dbus_bool_t use_subdir)
00242 {
00243     dbus_bool_t ret;
00244     DBusString randomStr;
00245 
00246     _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00247 
00248     _dbus_assert (noncefile);
00249 
00250     if (!_dbus_string_init (&randomStr))
00251       {
00252         dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00253         goto on_error;
00254       }
00255 
00256     if (!_dbus_generate_random_ascii (&randomStr, 8))
00257       {
00258         dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00259         goto on_error;
00260       }
00261 
00262     if (!_dbus_string_init (&noncefile->dir)
00263         || !_dbus_string_append (&noncefile->dir, _dbus_get_tmpdir()))
00264       {
00265         dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00266         goto on_error;
00267       }
00268     if (use_subdir)
00269       {
00270         if (!_dbus_string_append (&noncefile->dir, "/dbus_nonce-")
00271             || !_dbus_string_append (&noncefile->dir, _dbus_string_get_const_data (&randomStr)) )
00272           {
00273             dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00274             goto on_error;
00275           }
00276         if (!_dbus_string_init (&noncefile->path)
00277             || !_dbus_string_copy (&noncefile->dir, 0, &noncefile->path, 0)
00278             || !_dbus_string_append (&noncefile->path, "/nonce"))
00279           {
00280             dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00281             goto on_error;
00282           }
00283         if (!_dbus_create_directory (&noncefile->dir, error))
00284           {
00285             _DBUS_ASSERT_ERROR_IS_SET (error);
00286             goto on_error;
00287           }
00288         _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00289 
00290       }
00291     else
00292       {
00293         if (!_dbus_string_init (&noncefile->path)
00294             || !_dbus_string_copy (&noncefile->dir, 0, &noncefile->path, 0)
00295             || !_dbus_string_append (&noncefile->path, "/dbus_nonce-")
00296             || !_dbus_string_append (&noncefile->path, _dbus_string_get_const_data (&randomStr)))
00297           {
00298             dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00299             goto on_error;
00300           }
00301 
00302       }
00303 
00304     if (!generate_and_write_nonce (&noncefile->path, error))
00305       {
00306         _DBUS_ASSERT_ERROR_IS_SET (error);
00307         if (use_subdir)
00308           _dbus_delete_directory (&noncefile->dir, NULL); //we ignore possible errors deleting the dir and return the write error instead
00309         goto on_error;
00310       }
00311     _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00312 
00313     _dbus_string_free (&randomStr);
00314 
00315     return TRUE;
00316   on_error:
00317     if (use_subdir)
00318       _dbus_delete_directory (&noncefile->dir, NULL);
00319     _dbus_string_free (&noncefile->dir);
00320     _dbus_string_free (&noncefile->path);
00321     _dbus_string_free (&randomStr);
00322     return FALSE;
00323 }
00324 
00325 #ifdef DBUS_WIN
00326 
00333 dbus_bool_t
00334 _dbus_noncefile_create (DBusNonceFile *noncefile,
00335                         DBusError *error)
00336 {
00337     return do_noncefile_create (noncefile, error, /*use_subdir=*/FALSE);
00338 }
00339 
00347 dbus_bool_t
00348 _dbus_noncefile_delete (DBusNonceFile *noncefile,
00349                         DBusError *error)
00350 {
00351     _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00352 
00353     _dbus_delete_file (&noncefile->path, error);
00354     _dbus_string_free (&noncefile->dir);
00355     _dbus_string_free (&noncefile->path);
00356     return TRUE;
00357 }
00358 
00359 #else
00360 
00368 dbus_bool_t
00369 _dbus_noncefile_create (DBusNonceFile *noncefile,
00370                         DBusError *error)
00371 {
00372     return do_noncefile_create (noncefile, error, /*use_subdir=*/TRUE);
00373 }
00374 
00382 dbus_bool_t
00383 _dbus_noncefile_delete (DBusNonceFile *noncefile,
00384                         DBusError *error)
00385 {
00386     _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00387 
00388     _dbus_delete_directory (&noncefile->dir, error);
00389     _dbus_string_free (&noncefile->dir);
00390     _dbus_string_free (&noncefile->path);
00391     return TRUE;
00392 }
00393 #endif
00394 
00395 
00402 const DBusString*
00403 _dbus_noncefile_get_path (const DBusNonceFile *noncefile)
00404 {
00405     _dbus_assert (noncefile);
00406     return &noncefile->path;
00407 }
00408 
00419 dbus_bool_t
00420 _dbus_noncefile_check_nonce (int fd,
00421                              const DBusNonceFile *noncefile,
00422                              DBusError* error)
00423 {
00424     return do_check_nonce (fd, _dbus_noncefile_get_path (noncefile), error);
00425 }
00426 
00427