D-Bus 1.6.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 (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   DBusString nonce;
00200 
00201   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00202 
00203   if (_dbus_string_get_length (noncefile) == 0)
00204     return FALSE;
00205 
00206   if (!_dbus_string_init (&nonce))
00207     {
00208       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00209       return FALSE;
00210     }
00211 
00212   read_result = _dbus_read_nonce (noncefile, &nonce, error);
00213   if (!read_result)
00214     {
00215       _DBUS_ASSERT_ERROR_IS_SET (error);
00216       _dbus_string_free (&nonce);
00217       return FALSE;
00218     }
00219   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00220 
00221   send_result = _dbus_write_socket (fd, &nonce, 0, _dbus_string_get_length (&nonce));
00222 
00223   _dbus_string_free (&nonce);
00224 
00225   if (send_result == -1)
00226     {
00227       dbus_set_error (error,
00228                       _dbus_error_from_system_errno (),
00229                       "Failed to send nonce (fd=%d): %s",
00230                       fd, _dbus_strerror_from_errno ());
00231       return FALSE;
00232     }
00233 
00234   return TRUE;
00235 }
00236 
00237 static dbus_bool_t
00238 do_noncefile_create (DBusNonceFile *noncefile,
00239                      DBusError *error,
00240                      dbus_bool_t use_subdir)
00241 {
00242     DBusString randomStr;
00243 
00244     _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00245 
00246     _dbus_assert (noncefile);
00247 
00248     if (!_dbus_string_init (&randomStr))
00249       {
00250         dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00251         goto on_error;
00252       }
00253 
00254     if (!_dbus_generate_random_ascii (&randomStr, 8))
00255       {
00256         dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00257         goto on_error;
00258       }
00259 
00260     if (!_dbus_string_init (&noncefile->dir)
00261         || !_dbus_string_append (&noncefile->dir, _dbus_get_tmpdir()))
00262       {
00263         dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00264         goto on_error;
00265       }
00266     if (use_subdir)
00267       {
00268         if (!_dbus_string_append (&noncefile->dir, "/dbus_nonce-")
00269             || !_dbus_string_append (&noncefile->dir, _dbus_string_get_const_data (&randomStr)) )
00270           {
00271             dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00272             goto on_error;
00273           }
00274         if (!_dbus_string_init (&noncefile->path)
00275             || !_dbus_string_copy (&noncefile->dir, 0, &noncefile->path, 0)
00276             || !_dbus_string_append (&noncefile->path, "/nonce"))
00277           {
00278             dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00279             goto on_error;
00280           }
00281         if (!_dbus_create_directory (&noncefile->dir, error))
00282           {
00283             _DBUS_ASSERT_ERROR_IS_SET (error);
00284             goto on_error;
00285           }
00286         _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00287 
00288       }
00289     else
00290       {
00291         if (!_dbus_string_init (&noncefile->path)
00292             || !_dbus_string_copy (&noncefile->dir, 0, &noncefile->path, 0)
00293             || !_dbus_string_append (&noncefile->path, "/dbus_nonce-")
00294             || !_dbus_string_append (&noncefile->path, _dbus_string_get_const_data (&randomStr)))
00295           {
00296             dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00297             goto on_error;
00298           }
00299 
00300       }
00301 
00302     if (!generate_and_write_nonce (&noncefile->path, error))
00303       {
00304         _DBUS_ASSERT_ERROR_IS_SET (error);
00305         if (use_subdir)
00306           _dbus_delete_directory (&noncefile->dir, NULL); //we ignore possible errors deleting the dir and return the write error instead
00307         goto on_error;
00308       }
00309     _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00310 
00311     _dbus_string_free (&randomStr);
00312 
00313     return TRUE;
00314   on_error:
00315     if (use_subdir)
00316       _dbus_delete_directory (&noncefile->dir, NULL);
00317     _dbus_string_free (&noncefile->dir);
00318     _dbus_string_free (&noncefile->path);
00319     _dbus_string_free (&randomStr);
00320     return FALSE;
00321 }
00322 
00323 #ifdef DBUS_WIN
00324 
00331 dbus_bool_t
00332 _dbus_noncefile_create (DBusNonceFile *noncefile,
00333                         DBusError *error)
00334 {
00335     return do_noncefile_create (noncefile, error, /*use_subdir=*/FALSE);
00336 }
00337 
00345 dbus_bool_t
00346 _dbus_noncefile_delete (DBusNonceFile *noncefile,
00347                         DBusError *error)
00348 {
00349     _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00350 
00351     _dbus_delete_file (&noncefile->path, error);
00352     _dbus_string_free (&noncefile->dir);
00353     _dbus_string_free (&noncefile->path);
00354     return TRUE;
00355 }
00356 
00357 #else
00358 
00366 dbus_bool_t
00367 _dbus_noncefile_create (DBusNonceFile *noncefile,
00368                         DBusError *error)
00369 {
00370     return do_noncefile_create (noncefile, error, /*use_subdir=*/TRUE);
00371 }
00372 
00380 dbus_bool_t
00381 _dbus_noncefile_delete (DBusNonceFile *noncefile,
00382                         DBusError *error)
00383 {
00384     _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00385 
00386     _dbus_delete_directory (&noncefile->dir, error);
00387     _dbus_string_free (&noncefile->dir);
00388     _dbus_string_free (&noncefile->path);
00389     return TRUE;
00390 }
00391 #endif
00392 
00393 
00400 const DBusString*
00401 _dbus_noncefile_get_path (const DBusNonceFile *noncefile)
00402 {
00403     _dbus_assert (noncefile);
00404     return &noncefile->path;
00405 }
00406 
00417 dbus_bool_t
00418 _dbus_noncefile_check_nonce (int fd,
00419                              const DBusNonceFile *noncefile,
00420                              DBusError* error)
00421 {
00422     return do_check_nonce (fd, _dbus_noncefile_get_path (noncefile), error);
00423 }
00424 
00425