Don't use DBUS_DIR_SEPARATOR
[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 static int
137 accept_with_nonce (int listen_fd, const DBusString *nonce)
138 {
139
140 }
141
142 int
143 _dbus_accept_with_noncefile (int listen_fd, const DBusNonceFile *noncefile)
144 {
145   int fd;
146   DBusString nonce;
147
148   _dbus_assert (noncefile != NULL);
149   _dbus_string_init (&nonce);
150   //PENDING(kdab): set better errors
151   if (_dbus_read_nonce (_dbus_noncefile_get_path(noncefile), &nonce, NULL) != TRUE)
152     return -1;
153   fd = _dbus_accept (listen_fd);
154   if (_dbus_socket_is_invalid (fd))
155     return fd;
156   if (do_check_nonce(fd, &nonce, NULL) != TRUE) {
157     _dbus_verbose ("nonce check failed. Closing socket.\n");
158     _dbus_close_socket(fd, NULL);
159     return -1;
160   }
161
162   return fd;
163 }
164
165 static dbus_bool_t
166 generate_and_write_nonce (const DBusString *filename, DBusError *error)
167 {
168   DBusString nonce;
169   dbus_bool_t ret;
170
171   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
172
173   _dbus_string_init (&nonce);
174
175   if (!_dbus_generate_random_bytes (&nonce, 16))
176     {
177       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
178       _dbus_string_free (&nonce);
179       return FALSE;
180     }
181
182   ret = _dbus_string_save_to_file (&nonce, filename, error);
183
184   _dbus_string_free (&nonce);
185
186   return ret;
187 }
188
189 /**
190  * sends the nonce over a given socket. Blocks while doing so.
191  *
192  * @param fd the file descriptor to write the nonce data to (usually a socket)
193  * @param noncefile the noncefile location to read the nonce from
194  * @param error contains error details if FALSE is returned
195  * @return TRUE iff the nonce was successfully sent. Note that this does not
196  * indicate whether the server accepted the nonce.
197  */
198 dbus_bool_t
199 _dbus_send_nonce(int fd, const DBusString *noncefile, DBusError *error)
200 {
201   dbus_bool_t read_result;
202   int send_result;
203   size_t sendLen;
204   DBusString nonce;
205
206   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
207
208   if (_dbus_string_get_length (noncefile) == 0)
209     return FALSE;
210
211   if ( !_dbus_string_init (&nonce) )
212     {
213       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
214       return FALSE;
215   }
216
217   read_result = _dbus_read_nonce (noncefile, &nonce, NULL);
218
219   if (!read_result)
220     {
221       dbus_set_error (error,
222                       _dbus_error_from_errno (errno),
223                       "Could not read nonce from file %s (%s)",
224                       _dbus_string_get_const_data (noncefile), _dbus_strerror(errno));
225       _dbus_string_free (&nonce);
226       return FALSE;
227     }
228
229   send_result = _dbus_write_socket (fd, &nonce, 0, _dbus_string_get_length (&nonce));
230
231   _dbus_string_free (&nonce);
232
233   if (send_result == -1)
234   {
235     dbus_set_error (error,
236                     _dbus_error_from_errno (errno),
237                     "Failed to send nonce (fd=%d): %s",
238                     fd, _dbus_strerror(errno));
239     return FALSE;
240   }
241
242   return TRUE;
243 }
244
245 static dbus_bool_t
246 do_noncefile_create (DBusNonceFile *noncefile,
247                      DBusError *error,
248                      dbus_bool_t use_subdir)
249 {
250     dbus_bool_t ret;
251     DBusString randomStr;
252
253     _DBUS_ASSERT_ERROR_IS_CLEAR (error);
254
255     _dbus_assert (noncefile);
256
257     if (!_dbus_string_init (&randomStr))
258       {
259         dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
260         goto on_error;
261       }
262
263     if (!_dbus_generate_random_ascii (&randomStr, 8))
264       {
265         dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
266         goto on_error;
267       }
268
269     if (!_dbus_string_init (&noncefile->dir)
270         || !_dbus_string_append (&noncefile->dir, _dbus_get_tmpdir()))
271       {
272         dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
273         goto on_error;
274       }
275     if (use_subdir)
276       {
277         if (!_dbus_string_append (&noncefile->dir, "/dbus_nonce-")
278             || !_dbus_string_append (&noncefile->dir, _dbus_string_get_const_data (&randomStr)) )
279           {
280             dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
281             goto on_error;
282           }
283         if (!_dbus_string_init (&noncefile->path)
284             || !_dbus_string_copy (&noncefile->dir, 0, &noncefile->path, 0)
285             || !_dbus_string_append (&noncefile->dir, "/nonce"))
286           {
287             dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
288             goto on_error;
289           }
290         if (!_dbus_create_directory (&noncefile->dir, error))
291           {
292             goto on_error;
293           }
294
295       }
296     else
297       {
298         if (!_dbus_string_init (&noncefile->path)
299             || !_dbus_string_copy (&noncefile->dir, 0, &noncefile->path, 0)
300             || !_dbus_string_append (&noncefile->path, "/dbus_nonce-")
301             || !_dbus_string_append (&noncefile->path, _dbus_string_get_const_data (&randomStr)))
302           {
303             dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
304             goto on_error;
305           }
306
307       }
308
309     if (!generate_and_write_nonce (&noncefile->path, error))
310       {
311         if (use_subdir)
312           _dbus_delete_directory (&noncefile->dir, NULL); //we ignore possible errors deleting the dir and return the write error instead
313         goto on_error;
314       }
315
316     _dbus_string_free (&randomStr);
317
318     return TRUE;
319   on_error:
320     if (use_subdir)
321       _dbus_delete_directory (&noncefile->dir, NULL);
322     _dbus_string_free (&noncefile->dir);
323     _dbus_string_free (&noncefile->path);
324     _dbus_string_free (&randomStr);
325     return FALSE;
326 }
327
328 #ifdef DBUS_WIN
329 /**
330  * creates a nonce file in a user-readable location and writes a generated nonce to it
331  *
332  * @param noncefile returns the nonce file location
333  * @param error error details if creating the nonce file fails
334  * @return TRUE iff the nonce file was successfully created
335  */
336 dbus_bool_t
337 _dbus_noncefile_create (DBusNonceFile *noncefile,
338                         DBusError *error)
339 {
340     return do_noncefile_create (noncefile, error, /*use_subdir=*/FALSE);
341 }
342
343 /**
344  * deletes the noncefile and frees the DBusNonceFile object.
345  *
346  * @param noncefile the nonce file to delete. Contents will be freed.
347  * @param error error details if the nonce file could not be deleted
348  * @return TRUE
349  */
350 dbus_bool_t
351 _dbus_noncefile_delete (DBusNonceFile *noncefile,
352                         DBusError *error)
353 {
354     _DBUS_ASSERT_ERROR_IS_CLEAR (error);
355
356     _dbus_delete_file (&noncefile->path, error);
357     _dbus_string_free (&noncefile->dir);
358     _dbus_string_free (&noncefile->path);
359     return TRUE;
360 }
361
362 #else
363 /**
364  * creates a nonce file in a user-readable location and writes a generated nonce to it.
365  * Initializes the noncefile object.
366  *
367  * @param noncefile returns the nonce file location
368  * @param error error details if creating the nonce file fails
369  * @return TRUE iff the nonce file was successfully created
370  */
371 dbus_bool_t
372 _dbus_noncefile_create (DBusNonceFile *noncefile,
373                         DBusError *error)
374 {
375     return do_noncefile_create (noncefile, error, /*use_subdir=*/TRUE);
376 }
377
378 /**
379  * deletes the noncefile and frees the DBusNonceFile object.
380  *
381  * @param noncefile the nonce file to delete. Contents will be freed.
382  * @param error error details if the nonce file could not be deleted
383  * @return TRUE
384  */
385 dbus_bool_t
386 _dbus_noncefile_delete (DBusNonceFile *noncefile,
387                         DBusError *error)
388 {
389     _DBUS_ASSERT_ERROR_IS_CLEAR (error);
390
391     _dbus_delete_directory (&noncefile->dir, error);
392     _dbus_string_free (&noncefile->dir);
393     _dbus_string_free (&noncefile->path);
394     return TRUE;
395 }
396 #endif
397
398
399 /**
400  * returns the absolute file path of the nonce file
401  *
402  * @param noncefile an initialized noncefile object
403  * @return the absolute path of the nonce file
404  */
405 const DBusString*
406 _dbus_noncefile_get_path (const DBusNonceFile *noncefile)
407 {
408     _dbus_assert (noncefile);
409     return &noncefile->path;
410 }
411
412 /**
413  * reads data from a file descriptor and checks if the received data matches
414  * the data in the given noncefile.
415  *
416  * @param fd the file descriptor to read the nonce from
417  * @param noncefile the nonce file to check the received data against
418  * @param error error details on fail
419  * @return TRUE iff a nonce could be successfully read from the file descriptor
420  * and matches the nonce from the given nonce file
421  */
422 dbus_bool_t
423 _dbus_noncefile_check_nonce (int fd,
424                              const DBusNonceFile *noncefile,
425                              DBusError* error)
426 {
427     return do_check_nonce (fd, _dbus_noncefile_get_path (noncefile), error);
428 }
429
430
431 /** @} end of nonce */