Cleanup of nonce code
[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 #ifndef ENOFILE
37 # define ENOFILE ENOENT
38 #endif
39
40 dbus_bool_t
41 _dbus_check_nonce (int fd, const DBusString *nonce)
42 {
43   DBusString buffer;
44   DBusString p;
45   size_t nleft;
46   dbus_bool_t result;
47   int n;
48
49   nleft = 16;
50
51   _dbus_string_init (&buffer);
52   _dbus_string_init (&p);
53 //PENDING(kdab) replace errno by DBusError
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_string_free (&p);
64           _dbus_string_free (&buffer);
65           return FALSE;
66         }
67       else if (!n)
68         {
69         _dbus_string_free (&p);
70         _dbus_string_free (&buffer);
71           errno = EIO;
72           return FALSE;
73         }
74       else
75         {
76           _dbus_string_append_len(&buffer, _dbus_string_get_const_data (&p), n);
77           nleft -= n;
78         }
79     }
80
81   result =  _dbus_string_equal_len (&buffer, nonce, 16);
82   if (!result)
83       errno = EACCES;
84
85   _dbus_string_free (&p);
86   _dbus_string_free (&buffer);
87
88   return result;
89 }
90
91 //PENDING(kdab) document
92 dbus_bool_t
93 _dbus_read_nonce (const DBusString *fname, DBusString *nonce)
94 {
95   //PENDING(kdab) replace errno by DBusError
96   FILE *fp;
97   char buffer[17];
98   buffer[sizeof buffer - 1] = '\0';
99   size_t nread;
100   _dbus_verbose ("reading nonce from file: %s\n", _dbus_string_get_const_data (fname));
101
102
103   fp = fopen (_dbus_string_get_const_data (fname), "rb");
104   if (!fp)
105     return FALSE;
106   nread = fread (buffer, 1, sizeof buffer - 1, fp);
107   fclose (fp);
108   if (!nread)
109     {
110       errno = ENOFILE;
111       return FALSE;
112     }
113
114   if (!_dbus_string_append_len (nonce, buffer, sizeof buffer - 1 ))
115     {
116       errno = ENOMEM;
117       return FALSE;
118     }
119   return TRUE;
120 }
121
122 int
123 _dbus_accept_with_nonce (int listen_fd, const DBusString *nonce)
124 {
125   _dbus_assert (nonce != NULL);
126   int fd;
127   fd = _dbus_accept (listen_fd);
128   if (_dbus_socket_is_invalid (fd))
129     return fd;
130   if (_dbus_check_nonce(fd, nonce) != TRUE) {
131     _dbus_verbose ("nonce check failed. Closing socket.\n");
132     _dbus_close_socket(fd, NULL);
133     return -1;
134   }
135
136   return fd;
137 }
138
139 int
140 _dbus_accept_with_noncefile (int listen_fd, const DBusString *noncefile)
141 {
142   _dbus_assert (noncefile != NULL);
143   DBusString nonce;
144   _dbus_string_init (&nonce);
145   //PENDING(kdab): set better errors
146   if (_dbus_read_nonce (noncefile, &nonce) != TRUE)
147     return -1;
148   return _dbus_accept_with_nonce (listen_fd, &nonce);
149 }
150
151 dbus_bool_t
152 _dbus_generate_noncefilename (DBusString *buf, DBusError *error)
153 {
154   dbus_bool_t ret;
155   DBusString randomStr;
156
157   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
158
159   ret = _dbus_string_init (&randomStr);
160   if (!ret)
161     goto oom;
162   ret = _dbus_generate_random_ascii (&randomStr, 8);
163   if (!ret)
164     goto oom;
165   if (!_dbus_string_append (buf, _dbus_get_tmpdir())
166       || !_dbus_string_append (buf, DBUS_DIR_SEPARATOR "dbus_nonce-")
167       || !_dbus_string_append (buf, _dbus_string_get_const_data (&randomStr)) )
168     goto oom;
169
170   _dbus_string_free (&randomStr);
171   return TRUE;
172 oom:
173   dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
174   _dbus_string_free (&randomStr);
175   return FALSE;
176 }
177
178 dbus_bool_t
179 _dbus_generate_and_write_nonce (const DBusString *filename, DBusError *error)
180 {
181   DBusString nonce;
182   dbus_bool_t ret;
183
184   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
185
186   _dbus_string_init (&nonce);
187
188   if (!_dbus_generate_random_bytes (&nonce, 16))
189     {
190       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
191       _dbus_string_free (&nonce);
192       return FALSE;
193     }
194
195   ret = _dbus_string_save_to_file (filename, &nonce, error);
196
197   _dbus_string_free (&nonce);
198
199   return ret;
200 }
201
202 dbus_bool_t
203 _dbus_send_nonce(int fd, const DBusString *noncefile, DBusError *error)
204 {
205   dbus_bool_t read_result;
206   int send_result;
207   size_t sendLen;
208   DBusString nonce;
209
210   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
211
212   if (_dbus_string_get_length (noncefile) == 0)
213     return FALSE;
214
215   if ( !_dbus_string_init (&nonce) )
216     {
217       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
218       return FALSE;
219   }
220
221   read_result = _dbus_read_nonce (noncefile, &nonce);
222
223   if (!read_result)
224     {
225       dbus_set_error (error,
226                       _dbus_error_from_errno (errno),
227                       "Could not read nonce from file %s (%s)",
228                       _dbus_string_get_const_data (noncefile), _dbus_strerror(errno));
229       _dbus_string_free (&nonce);
230       return FALSE;
231     }
232
233   send_result = _dbus_write_socket (fd, &nonce, 0, _dbus_string_get_length (&nonce));
234
235   _dbus_string_free (&nonce);
236
237   if (send_result == -1)
238   {
239     dbus_set_error (error,
240                     _dbus_error_from_errno (errno),
241                     "Failed to send nonce (fd=%d): %s",
242                     fd, _dbus_strerror(errno));
243     return FALSE;
244   }
245
246   return TRUE;
247 }
248
249 /** @} end of nonce */