~ubuntu-branches/ubuntu/maverick/dbus/maverick-security

« back to all changes in this revision

Viewing changes to dbus/dbus-nonce.c

  • Committer: Bazaar Package Importer
  • Author(s): Jonathan Riddell
  • Date: 2010-09-27 13:06:32 UTC
  • mfrom: (1.1.23 upstream)
  • Revision ID: james.westby@ubuntu.com-20100927130632-bqs145trvchd2lmf
Tags: 1.4.0-0ubuntu1
* New upstream release
 - Fixes https://bugs.freedesktop.org/show_bug.cgi?id=17754 Race condition in protected_change_timeout
 - Requested by various upstream KDE developers http://lists.kde.org/?t=128514970000004&r=1&w=2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 (int 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
  if (   !_dbus_string_init (&buffer)
 
47
      || !_dbus_string_init (&p) ) {
 
48
        dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
 
49
        _dbus_string_free (&p);
 
50
        _dbus_string_free (&buffer);
 
51
        return FALSE;
 
52
      }
 
53
 
 
54
  while (nleft)
 
55
    {
 
56
      n = _dbus_read_socket (fd, &p, nleft);
 
57
      if (n == -1 && _dbus_get_is_errno_eintr())
 
58
        ;
 
59
      else if (n == -1 && _dbus_get_is_errno_eagain_or_ewouldblock())
 
60
        _dbus_sleep_milliseconds (100);
 
61
      else if (n==-1)
 
62
        {
 
63
          dbus_set_error (error, DBUS_ERROR_IO_ERROR, "Could not read nonce from socket (fd=%d)", fd );
 
64
          _dbus_string_free (&p);
 
65
          _dbus_string_free (&buffer);
 
66
          return FALSE;
 
67
        }
 
68
      else if (!n)
 
69
        {
 
70
          _dbus_string_free (&p);
 
71
          _dbus_string_free (&buffer);
 
72
          dbus_set_error (error, DBUS_ERROR_IO_ERROR, "Could not read nonce from socket (fd=%d)", fd );
 
73
          return FALSE;
 
74
        }
 
75
      else
 
76
        {
 
77
          _dbus_string_append_len(&buffer, _dbus_string_get_const_data (&p), n);
 
78
          nleft -= n;
 
79
        }
 
80
    }
 
81
 
 
82
  result =  _dbus_string_equal_len (&buffer, nonce, 16);
 
83
  if (!result)
 
84
    dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, "Nonces do not match, access denied (fd=%d)", fd );
 
85
 
 
86
  _dbus_string_free (&p);
 
87
  _dbus_string_free (&buffer);
 
88
 
 
89
  return result;
 
90
}
 
91
 
 
92
/**
 
93
 * reads the nonce from the nonce file and stores it in a string
 
94
 *
 
95
 * @param fname the file to read the nonce from
 
96
 * @param nonce returns the nonce. Must be an initialized string, the nonce will be appended.
 
97
 * @param error error object to report possible errors
 
98
 * @return FALSE iff reading the nonce fails (error is set then)
 
99
 */
 
100
dbus_bool_t
 
101
_dbus_read_nonce (const DBusString *fname, DBusString *nonce, DBusError* error)
 
102
{
 
103
  FILE *fp;
 
104
  char buffer[17];
 
105
  size_t nread;
 
106
 
 
107
  buffer[sizeof buffer - 1] = '\0';
 
108
 
 
109
  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
110
 
 
111
  _dbus_verbose ("reading nonce from file: %s\n", _dbus_string_get_const_data (fname));
 
112
 
 
113
 
 
114
  fp = fopen (_dbus_string_get_const_data (fname), "rb");
 
115
  if (!fp)
 
116
    return FALSE;
 
117
  nread = fread (buffer, 1, sizeof buffer - 1, fp);
 
118
  fclose (fp);
 
119
  if (!nread)
 
120
    {
 
121
      dbus_set_error (error, DBUS_ERROR_FILE_NOT_FOUND, "Could not read nonce from file %s", _dbus_string_get_const_data (fname));
 
122
      return FALSE;
 
123
    }
 
124
 
 
125
  if (!_dbus_string_append_len (nonce, buffer, sizeof buffer - 1 ))
 
126
    {
 
127
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
 
128
      return FALSE;
 
129
    }
 
130
  return TRUE;
 
131
}
 
132
 
 
133
int
 
134
_dbus_accept_with_noncefile (int listen_fd, const DBusNonceFile *noncefile)
 
135
{
 
136
  int fd;
 
137
  DBusString nonce;
 
138
 
 
139
  _dbus_assert (noncefile != NULL);
 
140
  _dbus_string_init (&nonce);
 
141
  //PENDING(kdab): set better errors
 
142
  if (_dbus_read_nonce (_dbus_noncefile_get_path(noncefile), &nonce, NULL) != TRUE)
 
143
    return -1;
 
144
  fd = _dbus_accept (listen_fd);
 
145
  if (_dbus_socket_is_invalid (fd))
 
146
    return fd;
 
147
  if (do_check_nonce(fd, &nonce, NULL) != TRUE) {
 
148
    _dbus_verbose ("nonce check failed. Closing socket.\n");
 
149
    _dbus_close_socket(fd, NULL);
 
150
    return -1;
 
151
  }
 
152
 
 
153
  return fd;
 
154
}
 
155
 
 
156
static dbus_bool_t
 
157
generate_and_write_nonce (const DBusString *filename, DBusError *error)
 
158
{
 
159
  DBusString nonce;
 
160
  dbus_bool_t ret;
 
161
 
 
162
  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
163
 
 
164
  _dbus_string_init (&nonce);
 
165
 
 
166
  if (!_dbus_generate_random_bytes (&nonce, 16))
 
167
    {
 
168
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
 
169
      _dbus_string_free (&nonce);
 
170
      return FALSE;
 
171
    }
 
172
 
 
173
  ret = _dbus_string_save_to_file (&nonce, filename, FALSE, error);
 
174
 
 
175
  _dbus_string_free (&nonce);
 
176
 
 
177
  return ret;
 
178
}
 
179
 
 
180
/**
 
181
 * sends the nonce over a given socket. Blocks while doing so.
 
182
 *
 
183
 * @param fd the file descriptor to write the nonce data to (usually a socket)
 
184
 * @param noncefile the noncefile location to read the nonce from
 
185
 * @param error contains error details if FALSE is returned
 
186
 * @return TRUE iff the nonce was successfully sent. Note that this does not
 
187
 * indicate whether the server accepted the nonce.
 
188
 */
 
189
dbus_bool_t
 
190
_dbus_send_nonce (int fd, const DBusString *noncefile, DBusError *error)
 
191
{
 
192
  dbus_bool_t read_result;
 
193
  int send_result;
 
194
  size_t sendLen;
 
195
  DBusString nonce;
 
196
 
 
197
  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
198
 
 
199
  if (_dbus_string_get_length (noncefile) == 0)
 
200
    return FALSE;
 
201
 
 
202
  if (!_dbus_string_init (&nonce))
 
203
    {
 
204
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
 
205
      return FALSE;
 
206
    }
 
207
 
 
208
  read_result = _dbus_read_nonce (noncefile, &nonce, error);
 
209
  if (!read_result)
 
210
    {
 
211
      _DBUS_ASSERT_ERROR_IS_SET (error);
 
212
      _dbus_string_free (&nonce);
 
213
      return FALSE;
 
214
    }
 
215
  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
216
 
 
217
  send_result = _dbus_write_socket (fd, &nonce, 0, _dbus_string_get_length (&nonce));
 
218
 
 
219
  _dbus_string_free (&nonce);
 
220
 
 
221
  if (send_result == -1)
 
222
    {
 
223
      dbus_set_error (error,
 
224
                      _dbus_error_from_system_errno (),
 
225
                      "Failed to send nonce (fd=%d): %s",
 
226
                      fd, _dbus_strerror_from_errno ());
 
227
      return FALSE;
 
228
    }
 
229
 
 
230
  return TRUE;
 
231
}
 
232
 
 
233
static dbus_bool_t
 
234
do_noncefile_create (DBusNonceFile *noncefile,
 
235
                     DBusError *error,
 
236
                     dbus_bool_t use_subdir)
 
237
{
 
238
    dbus_bool_t ret;
 
239
    DBusString randomStr;
 
240
 
 
241
    _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
242
 
 
243
    _dbus_assert (noncefile);
 
244
 
 
245
    if (!_dbus_string_init (&randomStr))
 
246
      {
 
247
        dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
 
248
        goto on_error;
 
249
      }
 
250
 
 
251
    if (!_dbus_generate_random_ascii (&randomStr, 8))
 
252
      {
 
253
        dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
 
254
        goto on_error;
 
255
      }
 
256
 
 
257
    if (!_dbus_string_init (&noncefile->dir)
 
258
        || !_dbus_string_append (&noncefile->dir, _dbus_get_tmpdir()))
 
259
      {
 
260
        dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
 
261
        goto on_error;
 
262
      }
 
263
    if (use_subdir)
 
264
      {
 
265
        if (!_dbus_string_append (&noncefile->dir, "/dbus_nonce-")
 
266
            || !_dbus_string_append (&noncefile->dir, _dbus_string_get_const_data (&randomStr)) )
 
267
          {
 
268
            dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
 
269
            goto on_error;
 
270
          }
 
271
        if (!_dbus_string_init (&noncefile->path)
 
272
            || !_dbus_string_copy (&noncefile->dir, 0, &noncefile->path, 0)
 
273
            || !_dbus_string_append (&noncefile->dir, "/nonce"))
 
274
          {
 
275
            dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
 
276
            goto on_error;
 
277
          }
 
278
        if (!_dbus_create_directory (&noncefile->dir, error))
 
279
          {
 
280
            _DBUS_ASSERT_ERROR_IS_SET (error);
 
281
            goto on_error;
 
282
          }
 
283
        _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
284
 
 
285
      }
 
286
    else
 
287
      {
 
288
        if (!_dbus_string_init (&noncefile->path)
 
289
            || !_dbus_string_copy (&noncefile->dir, 0, &noncefile->path, 0)
 
290
            || !_dbus_string_append (&noncefile->path, "/dbus_nonce-")
 
291
            || !_dbus_string_append (&noncefile->path, _dbus_string_get_const_data (&randomStr)))
 
292
          {
 
293
            dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
 
294
            goto on_error;
 
295
          }
 
296
 
 
297
      }
 
298
 
 
299
    if (!generate_and_write_nonce (&noncefile->path, error))
 
300
      {
 
301
        _DBUS_ASSERT_ERROR_IS_SET (error);
 
302
        if (use_subdir)
 
303
          _dbus_delete_directory (&noncefile->dir, NULL); //we ignore possible errors deleting the dir and return the write error instead
 
304
        goto on_error;
 
305
      }
 
306
    _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
307
 
 
308
    _dbus_string_free (&randomStr);
 
309
 
 
310
    return TRUE;
 
311
  on_error:
 
312
    if (use_subdir)
 
313
      _dbus_delete_directory (&noncefile->dir, NULL);
 
314
    _dbus_string_free (&noncefile->dir);
 
315
    _dbus_string_free (&noncefile->path);
 
316
    _dbus_string_free (&randomStr);
 
317
    return FALSE;
 
318
}
 
319
 
 
320
#ifdef DBUS_WIN
 
321
/**
 
322
 * creates a nonce file in a user-readable location and writes a generated nonce to it
 
323
 *
 
324
 * @param noncefile returns the nonce file location
 
325
 * @param error error details if creating the nonce file fails
 
326
 * @return TRUE iff the nonce file was successfully created
 
327
 */
 
328
dbus_bool_t
 
329
_dbus_noncefile_create (DBusNonceFile *noncefile,
 
330
                        DBusError *error)
 
331
{
 
332
    return do_noncefile_create (noncefile, error, /*use_subdir=*/FALSE);
 
333
}
 
334
 
 
335
/**
 
336
 * deletes the noncefile and frees the DBusNonceFile object.
 
337
 *
 
338
 * @param noncefile the nonce file to delete. Contents will be freed.
 
339
 * @param error error details if the nonce file could not be deleted
 
340
 * @return TRUE
 
341
 */
 
342
dbus_bool_t
 
343
_dbus_noncefile_delete (DBusNonceFile *noncefile,
 
344
                        DBusError *error)
 
345
{
 
346
    _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
347
 
 
348
    _dbus_delete_file (&noncefile->path, error);
 
349
    _dbus_string_free (&noncefile->dir);
 
350
    _dbus_string_free (&noncefile->path);
 
351
    return TRUE;
 
352
}
 
353
 
 
354
#else
 
355
/**
 
356
 * creates a nonce file in a user-readable location and writes a generated nonce to it.
 
357
 * Initializes the noncefile object.
 
358
 *
 
359
 * @param noncefile returns the nonce file location
 
360
 * @param error error details if creating the nonce file fails
 
361
 * @return TRUE iff the nonce file was successfully created
 
362
 */
 
363
dbus_bool_t
 
364
_dbus_noncefile_create (DBusNonceFile *noncefile,
 
365
                        DBusError *error)
 
366
{
 
367
    return do_noncefile_create (noncefile, error, /*use_subdir=*/TRUE);
 
368
}
 
369
 
 
370
/**
 
371
 * deletes the noncefile and frees the DBusNonceFile object.
 
372
 *
 
373
 * @param noncefile the nonce file to delete. Contents will be freed.
 
374
 * @param error error details if the nonce file could not be deleted
 
375
 * @return TRUE
 
376
 */
 
377
dbus_bool_t
 
378
_dbus_noncefile_delete (DBusNonceFile *noncefile,
 
379
                        DBusError *error)
 
380
{
 
381
    _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
382
 
 
383
    _dbus_delete_directory (&noncefile->dir, error);
 
384
    _dbus_string_free (&noncefile->dir);
 
385
    _dbus_string_free (&noncefile->path);
 
386
    return TRUE;
 
387
}
 
388
#endif
 
389
 
 
390
 
 
391
/**
 
392
 * returns the absolute file path of the nonce file
 
393
 *
 
394
 * @param noncefile an initialized noncefile object
 
395
 * @return the absolute path of the nonce file
 
396
 */
 
397
const DBusString*
 
398
_dbus_noncefile_get_path (const DBusNonceFile *noncefile)
 
399
{
 
400
    _dbus_assert (noncefile);
 
401
    return &noncefile->path;
 
402
}
 
403
 
 
404
/**
 
405
 * reads data from a file descriptor and checks if the received data matches
 
406
 * the data in the given noncefile.
 
407
 *
 
408
 * @param fd the file descriptor to read the nonce from
 
409
 * @param noncefile the nonce file to check the received data against
 
410
 * @param error error details on fail
 
411
 * @return TRUE iff a nonce could be successfully read from the file descriptor
 
412
 * and matches the nonce from the given nonce file
 
413
 */
 
414
dbus_bool_t
 
415
_dbus_noncefile_check_nonce (int fd,
 
416
                             const DBusNonceFile *noncefile,
 
417
                             DBusError* error)
 
418
{
 
419
    return do_check_nonce (fd, _dbus_noncefile_get_path (noncefile), error);
 
420
}
 
421
 
 
422
 
 
423
/** @} end of nonce */