D-Bus  1.12.16
dbus-nonce.c
1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 /* dbus-nonce.c Nonce handling functions used by nonce-tcp (internal to D-Bus implementation)
3  *
4  * Copyright (C) 2009 Klaralvdalens Datakonsult AB, a KDAB Group company, info@kdab.net
5  *
6  * Licensed under the Academic Free License version 2.1
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21  *
22  */
23 
24 #include <config.h>
25 // major sections of this file are modified code from libassuan, (C) FSF
26 #include "dbus-nonce.h"
27 #include "dbus-internals.h"
28 #include "dbus-protocol.h"
29 #include "dbus-sysdeps.h"
30 
31 #include <stdio.h>
32 
33 static dbus_bool_t
34 do_check_nonce (DBusSocket fd, const DBusString *nonce, DBusError *error)
35 {
36  DBusString buffer;
37  DBusString p;
38  size_t nleft;
39  dbus_bool_t result;
40  int n;
41 
42  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
43 
44  nleft = 16;
45 
46  /* This is a trick to make it safe to call _dbus_string_free on these
47  * strings during error unwinding, even if allocating memory for them
48  * fails. A constant DBusString is considered to be valid to "free",
49  * even though there is nothing to free (of course the free operation
50  * is trivial, because it does not own its own buffer); but
51  * unlike a mutable DBusString, initializing a constant DBusString
52  * cannot fail.
53  *
54  * We must successfully re-initialize the strings to be mutable before
55  * writing to them, of course.
56  */
57  _dbus_string_init_const (&buffer, "");
58  _dbus_string_init_const (&p, "");
59 
60  if ( !_dbus_string_init (&buffer)
61  || !_dbus_string_init (&p) ) {
63  _dbus_string_free (&p);
64  _dbus_string_free (&buffer);
65  return FALSE;
66  }
67 
68  while (nleft)
69  {
70  int saved_errno;
71 
72  n = _dbus_read_socket (fd, &p, nleft);
73  saved_errno = _dbus_save_socket_errno ();
74 
75  if (n == -1 && _dbus_get_is_errno_eintr (saved_errno))
76  ;
77  else if (n == -1 && _dbus_get_is_errno_eagain_or_ewouldblock (saved_errno))
79  else if (n==-1)
80  {
81  dbus_set_error (error, DBUS_ERROR_IO_ERROR, "Could not read nonce from socket (fd=%" DBUS_SOCKET_FORMAT ")", _dbus_socket_printable (fd));
82  _dbus_string_free (&p);
83  _dbus_string_free (&buffer);
84  return FALSE;
85  }
86  else if (!n)
87  {
88  _dbus_string_free (&p);
89  _dbus_string_free (&buffer);
90  dbus_set_error (error, DBUS_ERROR_IO_ERROR, "Could not read nonce from socket (fd=%" DBUS_SOCKET_FORMAT ")", _dbus_socket_printable (fd));
91  return FALSE;
92  }
93  else
94  {
96  {
98  _dbus_string_free (&p);
99  _dbus_string_free (&buffer);
100  return FALSE;
101  }
102  nleft -= n;
103  }
104  }
105 
106  result = _dbus_string_equal_len (&buffer, nonce, 16);
107  if (!result)
108  dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, "Nonces do not match, access denied (fd=%" DBUS_SOCKET_FORMAT ")", _dbus_socket_printable (fd));
109 
110  _dbus_string_free (&p);
111  _dbus_string_free (&buffer);
112 
113  return result;
114 }
115 
125 _dbus_read_nonce (const DBusString *fname, DBusString *nonce, DBusError* error)
126 {
127  FILE *fp;
128  char buffer[17];
129  size_t nread;
130 
131  buffer[sizeof buffer - 1] = '\0';
132 
133  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
134 
135  _dbus_verbose ("reading nonce from file: %s\n", _dbus_string_get_const_data (fname));
136 
137 
138  fp = fopen (_dbus_string_get_const_data (fname), "rb");
139  if (!fp)
140  {
141  dbus_set_error (error,
143  "Failed to open %s for read: %s",
146  return FALSE;
147  }
148 
149  nread = fread (buffer, 1, sizeof buffer - 1, fp);
150  fclose (fp);
151  if (!nread)
152  {
153  dbus_set_error (error, DBUS_ERROR_FILE_NOT_FOUND, "Could not read nonce from file %s", _dbus_string_get_const_data (fname));
154  return FALSE;
155  }
156 
157  if (!_dbus_string_append_len (nonce, buffer, sizeof buffer - 1 ))
158  {
160  return FALSE;
161  }
162  return TRUE;
163 }
164 
166 _dbus_accept_with_noncefile (DBusSocket listen_fd, const DBusNonceFile *noncefile)
167 {
168  DBusSocket fd = _dbus_socket_get_invalid ();
169  DBusString nonce;
170 
171  _dbus_assert (noncefile != NULL);
172 
173  /* Make it valid to "free" this even if _dbus_string_init() runs
174  * out of memory: see comment in do_check_nonce() */
175  _dbus_string_init_const (&nonce, "");
176 
177  if (!_dbus_string_init (&nonce))
178  goto out;
179 
180  //PENDING(kdab): set better errors
181  if (_dbus_read_nonce (_dbus_noncefile_get_path(noncefile), &nonce, NULL) != TRUE)
182  goto out;
183 
184  fd = _dbus_accept (listen_fd);
185 
186  if (!_dbus_socket_is_valid (fd))
187  goto out;
188 
189  if (do_check_nonce(fd, &nonce, NULL) != TRUE) {
190  _dbus_verbose ("nonce check failed. Closing socket.\n");
192  _dbus_socket_invalidate (&fd);
193  goto out;
194  }
195 
196 out:
197  _dbus_string_free (&nonce);
198  return fd;
199 }
200 
201 static dbus_bool_t
202 generate_and_write_nonce (const DBusString *filename, DBusError *error)
203 {
204  DBusString nonce;
205  dbus_bool_t ret;
206 
207  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
208 
209  if (!_dbus_string_init (&nonce))
210  {
212  return FALSE;
213  }
214 
215  if (!_dbus_generate_random_bytes (&nonce, 16, error))
216  {
217  _dbus_string_free (&nonce);
218  return FALSE;
219  }
220 
221  ret = _dbus_string_save_to_file (&nonce, filename, FALSE, error);
222 
223  _dbus_string_free (&nonce);
224 
225  return ret;
226 }
227 
238 _dbus_send_nonce (DBusSocket fd,
239  const DBusString *noncefile,
240  DBusError *error)
241 {
242  dbus_bool_t read_result;
243  int send_result;
244  DBusString nonce;
245 
246  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
247 
248  if (_dbus_string_get_length (noncefile) == 0)
249  return FALSE;
250 
251  if (!_dbus_string_init (&nonce))
252  {
254  return FALSE;
255  }
256 
257  read_result = _dbus_read_nonce (noncefile, &nonce, error);
258  if (!read_result)
259  {
260  _DBUS_ASSERT_ERROR_IS_SET (error);
261  _dbus_string_free (&nonce);
262  return FALSE;
263  }
264  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
265 
266  send_result = _dbus_write_socket (fd, &nonce, 0, _dbus_string_get_length (&nonce));
267 
268  _dbus_string_free (&nonce);
269 
270  if (send_result == -1)
271  {
272  dbus_set_error (error,
274  "Failed to send nonce (fd=%" DBUS_SOCKET_FORMAT "): %s",
275  _dbus_socket_printable (fd),
277  return FALSE;
278  }
279 
280  return TRUE;
281 }
282 
283 static dbus_bool_t
284 do_noncefile_create (DBusNonceFile *noncefile,
285  DBusError *error,
286  dbus_bool_t use_subdir)
287 {
288  DBusString randomStr;
289  const char *tmp;
290 
291  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
292 
293  _dbus_assert (noncefile);
294 
295  /* Make it valid to "free" these even if _dbus_string_init() runs
296  * out of memory: see comment in do_check_nonce() */
297  _dbus_string_init_const (&randomStr, "");
298  _dbus_string_init_const (&noncefile->dir, "");
299  _dbus_string_init_const (&noncefile->path, "");
300 
301  if (!_dbus_string_init (&randomStr))
302  {
304  goto on_error;
305  }
306 
307  if (!_dbus_generate_random_ascii (&randomStr, 8, error))
308  {
309  goto on_error;
310  }
311 
312  tmp = _dbus_get_tmpdir ();
313 
314  if (!_dbus_string_init (&noncefile->dir)
315  || tmp == NULL
316  || !_dbus_string_append (&noncefile->dir, tmp))
317  {
319  goto on_error;
320  }
321  if (use_subdir)
322  {
323  if (!_dbus_string_append (&noncefile->dir, "/dbus_nonce-")
324  || !_dbus_string_append (&noncefile->dir, _dbus_string_get_const_data (&randomStr)) )
325  {
327  goto on_error;
328  }
329  if (!_dbus_string_init (&noncefile->path)
330  || !_dbus_string_copy (&noncefile->dir, 0, &noncefile->path, 0)
331  || !_dbus_string_append (&noncefile->path, "/nonce"))
332  {
334  goto on_error;
335  }
336  if (!_dbus_create_directory (&noncefile->dir, error))
337  {
338  _DBUS_ASSERT_ERROR_IS_SET (error);
339  goto on_error;
340  }
341  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
342 
343  }
344  else
345  {
346  if (!_dbus_string_init (&noncefile->path)
347  || !_dbus_string_copy (&noncefile->dir, 0, &noncefile->path, 0)
348  || !_dbus_string_append (&noncefile->path, "/dbus_nonce-")
349  || !_dbus_string_append (&noncefile->path, _dbus_string_get_const_data (&randomStr)))
350  {
352  goto on_error;
353  }
354 
355  }
356 
357  if (!generate_and_write_nonce (&noncefile->path, error))
358  {
359  _DBUS_ASSERT_ERROR_IS_SET (error);
360  if (use_subdir)
361  _dbus_delete_directory (&noncefile->dir, NULL); //we ignore possible errors deleting the dir and return the write error instead
362  goto on_error;
363  }
364  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
365 
366  _dbus_string_free (&randomStr);
367 
368  return TRUE;
369  on_error:
370  if (use_subdir && _dbus_string_get_length (&noncefile->dir) != 0)
371  _dbus_delete_directory (&noncefile->dir, NULL);
372  _dbus_string_free (&noncefile->dir);
373  _dbus_string_free (&noncefile->path);
374  _dbus_string_free (&randomStr);
375  return FALSE;
376 }
377 
378 #ifdef DBUS_WIN
379 
387 _dbus_noncefile_create (DBusNonceFile *noncefile,
388  DBusError *error)
389 {
390  return do_noncefile_create (noncefile, error, /*use_subdir=*/FALSE);
391 }
392 
401 _dbus_noncefile_delete (DBusNonceFile *noncefile,
402  DBusError *error)
403 {
404  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
405 
406  _dbus_delete_file (&noncefile->path, error);
407  _dbus_string_free (&noncefile->dir);
408  _dbus_string_free (&noncefile->path);
409  return TRUE;
410 }
411 
412 #else
413 
422 _dbus_noncefile_create (DBusNonceFile *noncefile,
423  DBusError *error)
424 {
425  return do_noncefile_create (noncefile, error, /*use_subdir=*/TRUE);
426 }
427 
436 _dbus_noncefile_delete (DBusNonceFile *noncefile,
437  DBusError *error)
438 {
439  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
440 
441  _dbus_delete_directory (&noncefile->dir, error);
442  _dbus_string_free (&noncefile->dir);
443  _dbus_string_free (&noncefile->path);
444  return TRUE;
445 }
446 #endif
447 
448 
455 const DBusString*
456 _dbus_noncefile_get_path (const DBusNonceFile *noncefile)
457 {
458  _dbus_assert (noncefile);
459  return &noncefile->path;
460 }
461 
473 _dbus_noncefile_check_nonce (DBusSocket fd,
474  const DBusNonceFile *noncefile,
475  DBusError* error)
476 {
477  return do_check_nonce (fd, _dbus_noncefile_get_path (noncefile), error);
478 }
479 
480