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