D-Bus  1.8.20
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           if (!_dbus_string_append_len (&buffer, _dbus_string_get_const_data (&p), n))
00078             {
00079               dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00080               _dbus_string_free (&p);
00081               _dbus_string_free (&buffer);
00082               return FALSE;
00083             }
00084           nleft -= n;
00085         }
00086     }
00087 
00088   result =  _dbus_string_equal_len (&buffer, nonce, 16);
00089   if (!result)
00090     dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, "Nonces do not match, access denied (fd=%d)", fd );
00091 
00092   _dbus_string_free (&p);
00093   _dbus_string_free (&buffer);
00094 
00095   return result;
00096 }
00097 
00106 dbus_bool_t
00107 _dbus_read_nonce (const DBusString *fname, DBusString *nonce, DBusError* error)
00108 {
00109   FILE *fp;
00110   char buffer[17];
00111   size_t nread;
00112 
00113   buffer[sizeof buffer - 1] = '\0';
00114 
00115   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00116 
00117   _dbus_verbose ("reading nonce from file: %s\n", _dbus_string_get_const_data (fname));
00118 
00119 
00120   fp = fopen (_dbus_string_get_const_data (fname), "rb");
00121   if (!fp)
00122     {
00123       dbus_set_error (error,
00124                       _dbus_error_from_system_errno (),
00125                       "Failed to open %s for read: %s",
00126                       _dbus_string_get_const_data (fname),
00127                       _dbus_strerror_from_errno ());
00128       return FALSE;
00129     }
00130 
00131   nread = fread (buffer, 1, sizeof buffer - 1, fp);
00132   fclose (fp);
00133   if (!nread)
00134     {
00135       dbus_set_error (error, DBUS_ERROR_FILE_NOT_FOUND, "Could not read nonce from file %s", _dbus_string_get_const_data (fname));
00136       return FALSE;
00137     }
00138 
00139   if (!_dbus_string_append_len (nonce, buffer, sizeof buffer - 1 ))
00140     {
00141       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00142       return FALSE;
00143     }
00144   return TRUE;
00145 }
00146 
00147 int
00148 _dbus_accept_with_noncefile (int listen_fd, const DBusNonceFile *noncefile)
00149 {
00150   int fd;
00151   DBusString nonce;
00152 
00153   _dbus_assert (noncefile != NULL);
00154   if (!_dbus_string_init (&nonce))
00155     return -1;
00156   //PENDING(kdab): set better errors
00157   if (_dbus_read_nonce (_dbus_noncefile_get_path(noncefile), &nonce, NULL) != TRUE)
00158     return -1;
00159   fd = _dbus_accept (listen_fd);
00160   if (_dbus_socket_is_invalid (fd))
00161     return fd;
00162   if (do_check_nonce(fd, &nonce, NULL) != TRUE) {
00163     _dbus_verbose ("nonce check failed. Closing socket.\n");
00164     _dbus_close_socket(fd, NULL);
00165     return -1;
00166   }
00167 
00168   return fd;
00169 }
00170 
00171 static dbus_bool_t
00172 generate_and_write_nonce (const DBusString *filename, DBusError *error)
00173 {
00174   DBusString nonce;
00175   dbus_bool_t ret;
00176 
00177   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00178 
00179   if (!_dbus_string_init (&nonce))
00180     {
00181       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00182       return FALSE;
00183     }
00184 
00185   if (!_dbus_generate_random_bytes (&nonce, 16))
00186     {
00187       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00188       _dbus_string_free (&nonce);
00189       return FALSE;
00190     }
00191 
00192   ret = _dbus_string_save_to_file (&nonce, filename, FALSE, error);
00193 
00194   _dbus_string_free (&nonce);
00195 
00196   return ret;
00197 }
00198 
00208 dbus_bool_t
00209 _dbus_send_nonce (int fd, const DBusString *noncefile, DBusError *error)
00210 {
00211   dbus_bool_t read_result;
00212   int send_result;
00213   DBusString nonce;
00214 
00215   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00216 
00217   if (_dbus_string_get_length (noncefile) == 0)
00218     return FALSE;
00219 
00220   if (!_dbus_string_init (&nonce))
00221     {
00222       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00223       return FALSE;
00224     }
00225 
00226   read_result = _dbus_read_nonce (noncefile, &nonce, error);
00227   if (!read_result)
00228     {
00229       _DBUS_ASSERT_ERROR_IS_SET (error);
00230       _dbus_string_free (&nonce);
00231       return FALSE;
00232     }
00233   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00234 
00235   send_result = _dbus_write_socket (fd, &nonce, 0, _dbus_string_get_length (&nonce));
00236 
00237   _dbus_string_free (&nonce);
00238 
00239   if (send_result == -1)
00240     {
00241       dbus_set_error (error,
00242                       _dbus_error_from_system_errno (),
00243                       "Failed to send nonce (fd=%d): %s",
00244                       fd, _dbus_strerror_from_errno ());
00245       return FALSE;
00246     }
00247 
00248   return TRUE;
00249 }
00250 
00251 static dbus_bool_t
00252 do_noncefile_create (DBusNonceFile *noncefile,
00253                      DBusError *error,
00254                      dbus_bool_t use_subdir)
00255 {
00256     DBusString randomStr;
00257     const char *tmp;
00258 
00259     _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00260 
00261     _dbus_assert (noncefile);
00262 
00263     if (!_dbus_string_init (&randomStr))
00264       {
00265         dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00266         goto on_error;
00267       }
00268 
00269     if (!_dbus_generate_random_ascii (&randomStr, 8))
00270       {
00271         dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00272         goto on_error;
00273       }
00274 
00275     tmp = _dbus_get_tmpdir ();
00276 
00277     if (!_dbus_string_init (&noncefile->dir)
00278         || tmp == NULL
00279         || !_dbus_string_append (&noncefile->dir, tmp))
00280       {
00281         dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00282         goto on_error;
00283       }
00284     if (use_subdir)
00285       {
00286         if (!_dbus_string_append (&noncefile->dir, "/dbus_nonce-")
00287             || !_dbus_string_append (&noncefile->dir, _dbus_string_get_const_data (&randomStr)) )
00288           {
00289             dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00290             goto on_error;
00291           }
00292         if (!_dbus_string_init (&noncefile->path)
00293             || !_dbus_string_copy (&noncefile->dir, 0, &noncefile->path, 0)
00294             || !_dbus_string_append (&noncefile->path, "/nonce"))
00295           {
00296             dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00297             goto on_error;
00298           }
00299         if (!_dbus_create_directory (&noncefile->dir, error))
00300           {
00301             _DBUS_ASSERT_ERROR_IS_SET (error);
00302             goto on_error;
00303           }
00304         _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00305 
00306       }
00307     else
00308       {
00309         if (!_dbus_string_init (&noncefile->path)
00310             || !_dbus_string_copy (&noncefile->dir, 0, &noncefile->path, 0)
00311             || !_dbus_string_append (&noncefile->path, "/dbus_nonce-")
00312             || !_dbus_string_append (&noncefile->path, _dbus_string_get_const_data (&randomStr)))
00313           {
00314             dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00315             goto on_error;
00316           }
00317 
00318       }
00319 
00320     if (!generate_and_write_nonce (&noncefile->path, error))
00321       {
00322         _DBUS_ASSERT_ERROR_IS_SET (error);
00323         if (use_subdir)
00324           _dbus_delete_directory (&noncefile->dir, NULL); //we ignore possible errors deleting the dir and return the write error instead
00325         goto on_error;
00326       }
00327     _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00328 
00329     _dbus_string_free (&randomStr);
00330 
00331     return TRUE;
00332   on_error:
00333     if (use_subdir)
00334       _dbus_delete_directory (&noncefile->dir, NULL);
00335     _dbus_string_free (&noncefile->dir);
00336     _dbus_string_free (&noncefile->path);
00337     _dbus_string_free (&randomStr);
00338     return FALSE;
00339 }
00340 
00341 #ifdef DBUS_WIN
00342 
00349 dbus_bool_t
00350 _dbus_noncefile_create (DBusNonceFile *noncefile,
00351                         DBusError *error)
00352 {
00353     return do_noncefile_create (noncefile, error, /*use_subdir=*/FALSE);
00354 }
00355 
00363 dbus_bool_t
00364 _dbus_noncefile_delete (DBusNonceFile *noncefile,
00365                         DBusError *error)
00366 {
00367     _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00368 
00369     _dbus_delete_file (&noncefile->path, error);
00370     _dbus_string_free (&noncefile->dir);
00371     _dbus_string_free (&noncefile->path);
00372     return TRUE;
00373 }
00374 
00375 #else
00376 
00384 dbus_bool_t
00385 _dbus_noncefile_create (DBusNonceFile *noncefile,
00386                         DBusError *error)
00387 {
00388     return do_noncefile_create (noncefile, error, /*use_subdir=*/TRUE);
00389 }
00390 
00398 dbus_bool_t
00399 _dbus_noncefile_delete (DBusNonceFile *noncefile,
00400                         DBusError *error)
00401 {
00402     _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00403 
00404     _dbus_delete_directory (&noncefile->dir, error);
00405     _dbus_string_free (&noncefile->dir);
00406     _dbus_string_free (&noncefile->path);
00407     return TRUE;
00408 }
00409 #endif
00410 
00411 
00418 const DBusString*
00419 _dbus_noncefile_get_path (const DBusNonceFile *noncefile)
00420 {
00421     _dbus_assert (noncefile);
00422     return &noncefile->path;
00423 }
00424 
00435 dbus_bool_t
00436 _dbus_noncefile_check_nonce (int fd,
00437                              const DBusNonceFile *noncefile,
00438                              DBusError* error)
00439 {
00440     return do_check_nonce (fd, _dbus_noncefile_get_path (noncefile), error);
00441 }
00442 
00443