D-Bus 1.6.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 (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