D-Bus
1.10.12
|
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