2003-02-10 Havoc Pennington <hp@pobox.com>
[platform/upstream/dbus.git] / dbus / dbus-auth-script.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-auth-script.c Test DBusAuth using a special script file (internal to D-BUS implementation)
3  * 
4  * Copyright (C) 2003 Red Hat, Inc.
5  *
6  * Licensed under the Academic Free License version 1.2
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 #include <config.h>
24
25 #ifdef DBUS_BUILD_TESTS
26
27 #include "dbus-auth-script.h"
28 #include "dbus-auth.h"
29 #include "dbus-string.h"
30 #include "dbus-hash.h"
31 #include "dbus-internals.h"
32 #include "dbus-marshal.h"
33
34 /**
35  * @defgroup DBusAuthScript code for running unit test scripts for DBusAuth
36  * @ingroup  DBusInternals
37  * @brief DBusAuth unit test scripting
38  *
39  * The code in here is used for unit testing, it loads
40  * up a script that tests DBusAuth.
41  *
42  * @{
43  */
44
45 static dbus_bool_t
46 append_quoted_string (DBusString       *dest,
47                       const DBusString *quoted)
48 {
49   dbus_bool_t in_quotes = FALSE;
50   int i;
51
52   i = 0;
53   while (i < _dbus_string_get_length (quoted))
54     {
55       unsigned char b;
56
57       b = _dbus_string_get_byte (quoted, i);
58       
59       if (in_quotes)
60         {
61           if (b == '\'')
62             in_quotes = FALSE;
63           else
64             {
65               if (!_dbus_string_append_byte (dest, b))
66                 return FALSE;
67             }
68         }
69       else
70         {
71           if (b == '\'')
72             in_quotes = TRUE;
73           else if (b == ' ' || b == '\n' || b == '\t')
74             break; /* end on whitespace if not quoted */
75           else
76             {
77               if (!_dbus_string_append_byte (dest, b))
78                 return FALSE;
79             }
80         }
81       
82       ++i;
83     }
84
85   if (!_dbus_string_append_byte (dest, '\0'))
86     return FALSE;
87   return TRUE;
88 }
89
90 static dbus_bool_t
91 same_first_word (const DBusString *a,
92                  const DBusString *b)
93 {
94   int first_a_blank, first_b_blank;
95
96   _dbus_string_find_blank (a, 0, &first_a_blank);
97   _dbus_string_find_blank (b, 0, &first_b_blank);
98
99   if (first_a_blank != first_b_blank)
100     return FALSE;
101
102   return _dbus_string_equal_len (a, b, first_a_blank);
103 }
104
105 static DBusAuthState
106 auth_state_from_string (const DBusString *str)
107
108   if (_dbus_string_starts_with_c_str (str, "WAITING_FOR_INPUT"))
109     return DBUS_AUTH_STATE_WAITING_FOR_INPUT;
110   else if (_dbus_string_starts_with_c_str (str, "WAITING_FOR_MEMORY"))
111     return DBUS_AUTH_STATE_WAITING_FOR_MEMORY;
112   else if (_dbus_string_starts_with_c_str (str, "HAVE_BYTES_TO_SEND"))
113     return DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND;
114   else if (_dbus_string_starts_with_c_str (str, "NEED_DISCONNECT"))
115     return DBUS_AUTH_STATE_NEED_DISCONNECT;
116   else if (_dbus_string_starts_with_c_str (str, "AUTHENTICATED_WITH_UNUSED_BYTES"))
117     return DBUS_AUTH_STATE_AUTHENTICATED_WITH_UNUSED_BYTES;
118   else if (_dbus_string_starts_with_c_str (str, "AUTHENTICATED"))
119     return DBUS_AUTH_STATE_AUTHENTICATED;
120   else
121     return -1;
122 }
123
124 static const char*
125 auth_state_to_string (DBusAuthState state)
126 {
127   switch (state)
128     {
129     case DBUS_AUTH_STATE_WAITING_FOR_INPUT:
130       return "WAITING_FOR_INPUT";
131     case DBUS_AUTH_STATE_WAITING_FOR_MEMORY:
132       return "WAITING_FOR_MEMORY";
133     case DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND:
134       return "HAVE_BYTES_TO_SEND";
135     case DBUS_AUTH_STATE_NEED_DISCONNECT:
136       return "NEED_DISCONNECT";
137     case DBUS_AUTH_STATE_AUTHENTICATED_WITH_UNUSED_BYTES:
138       return "AUTHENTICATED_WITH_UNUSED_BYTES";
139     case DBUS_AUTH_STATE_AUTHENTICATED:
140       return "AUTHENTICATED";
141     }
142
143   return "unknown";
144 }
145
146 dbus_bool_t
147 _dbus_auth_script_run (const DBusString *filename)
148 {
149   DBusString file;
150   DBusResultCode result;
151   DBusString line;
152   dbus_bool_t retval;
153   int line_no;
154   DBusAuth *auth;
155   DBusString from_auth;
156   DBusAuthState state;
157   
158   retval = FALSE;
159   auth = NULL;
160   
161   if (!_dbus_string_init (&file, _DBUS_INT_MAX))
162     return FALSE;
163
164   if (!_dbus_string_init (&line, _DBUS_INT_MAX))
165     {
166       _dbus_string_free (&file);
167       return FALSE;
168     }
169
170   if (!_dbus_string_init (&from_auth, _DBUS_INT_MAX))
171     {
172       _dbus_string_free (&file);
173       _dbus_string_free (&line);
174       return FALSE;
175     }
176   
177   if ((result = _dbus_file_get_contents (&file, filename)) != DBUS_RESULT_SUCCESS)
178     {
179       const char *s;
180       _dbus_string_get_const_data (filename, &s);
181       _dbus_warn ("Getting contents of %s failed: %s\n",
182                   s, dbus_result_to_string (result));
183                      
184       goto out;
185     }
186
187   state = DBUS_AUTH_STATE_NEED_DISCONNECT;
188   line_no = 0;
189  next_iteration:
190   while (_dbus_string_pop_line (&file, &line))
191     {      
192       line_no += 1;
193
194       _dbus_string_delete_leading_blanks (&line);
195
196       if (auth != NULL)
197         {
198           while ((state = _dbus_auth_do_work (auth)) ==
199                  DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND)
200             {
201               const DBusString *tmp;
202               if (_dbus_auth_get_bytes_to_send (auth, &tmp))
203                 {
204                   int count = _dbus_string_get_length (tmp);
205
206                   if (_dbus_string_copy (tmp, 0, &from_auth,
207                                          _dbus_string_get_length (&from_auth)))
208                     _dbus_auth_bytes_sent (auth, count);
209                 }
210             }
211         }
212       
213       if (_dbus_string_get_length (&line) == 0)
214         {
215           /* empty line */
216           goto next_iteration;
217         }
218       else if (_dbus_string_starts_with_c_str (&line,
219                                                "#"))
220         {
221           /* Ignore this comment */
222           goto next_iteration;
223         }
224       else if (_dbus_string_starts_with_c_str (&line,
225                                                "CLIENT"))
226         {
227           if (auth != NULL)
228             {
229               _dbus_warn ("already created a DBusAuth (CLIENT or SERVER given twice)\n");
230               goto out;
231             }
232
233           auth = _dbus_auth_client_new ();
234           if (auth == NULL)
235             {
236               _dbus_warn ("no memory to create DBusAuth\n");
237               goto out;
238             }
239         }
240       else if (_dbus_string_starts_with_c_str (&line,
241                                                "SERVER"))
242         {
243           if (auth != NULL)
244             {
245               _dbus_warn ("already created a DBusAuth (CLIENT or SERVER given twice)\n");
246               goto out;
247             }
248
249           auth = _dbus_auth_server_new ();
250           if (auth == NULL)
251             {
252               _dbus_warn ("no memory to create DBusAuth\n");
253               goto out;
254             }
255         }
256       else if (auth == NULL)
257         {
258           _dbus_warn ("must specify CLIENT or SERVER\n");
259           goto out;
260
261         }
262       else if (_dbus_string_starts_with_c_str (&line,
263                                                "SEND"))
264         {
265           DBusString to_send;
266           
267           _dbus_string_delete_first_word (&line);
268
269           if (!_dbus_string_init (&to_send, _DBUS_INT_MAX))
270             {
271               _dbus_warn ("no memory to allocate string\n");
272               goto out;
273             }
274
275           if (!append_quoted_string (&to_send, &line))
276             {
277               _dbus_warn ("failed to append quoted string line %d\n",
278                           line_no);
279               _dbus_string_free (&to_send);
280               goto out;
281             }
282
283           if (!_dbus_auth_bytes_received (auth, &to_send))
284             {
285               _dbus_warn ("not enough memory to call bytes_received\n");
286               _dbus_string_free (&to_send);
287               goto out;
288             }
289
290           _dbus_string_free (&to_send);
291         }
292       else if (_dbus_string_starts_with_c_str (&line,
293                                                "EXPECT_STATE"))
294         {
295           DBusAuthState expected;
296           
297           _dbus_string_delete_first_word (&line);
298
299           expected = auth_state_from_string (&line);
300           if (expected < 0)
301             {
302               _dbus_warn ("bad auth state given to EXPECT_STATE\n");
303               goto parse_failed;
304             }
305
306           if (expected != state)
307             {
308               _dbus_warn ("expected auth state %s but got %s on line %d\n",
309                           auth_state_to_string (expected),
310                           auth_state_to_string (state),
311                           line_no);
312               goto out;
313             }
314         }
315       else if (_dbus_string_starts_with_c_str (&line,
316                                                "EXPECT_COMMAND"))
317         {
318           DBusString received;
319           
320           _dbus_string_delete_first_word (&line);
321
322           if (!_dbus_string_init (&received, _DBUS_INT_MAX))
323             {
324               _dbus_warn ("no mem to allocate string received\n");
325               goto out;
326             }
327
328           if (!_dbus_string_pop_line (&from_auth, &received))
329             {
330               const char *command;
331               _dbus_string_get_const_data (&line, &command);
332               _dbus_warn ("no line popped from the DBusAuth being tested, expected command %s on line %d\n",
333                           command, line_no);
334               _dbus_string_free (&received);
335               goto out;
336             }
337
338           if (!same_first_word (&received, &line))
339             {
340               const char *s1, *s2;
341               _dbus_string_get_const_data (&line, &s1);
342               _dbus_string_get_const_data (&received, &s2);
343               _dbus_warn ("expected command '%s' and got '%s' line %d\n",
344                           s1, s2, line_no);
345               _dbus_string_free (&received);
346               goto out;
347             }
348           
349           _dbus_string_free (&received);
350         }
351       else
352         goto parse_failed;
353
354       goto next_iteration; /* skip parse_failed */
355       
356     parse_failed:
357       {
358         const char *s;
359         _dbus_string_get_const_data (&line, &s);
360         _dbus_warn ("couldn't process line %d \"%s\"\n",
361                     line_no, s);
362         goto out;
363       }
364     }
365
366   if (auth != NULL &&
367       state == DBUS_AUTH_STATE_AUTHENTICATED_WITH_UNUSED_BYTES)
368     {
369       _dbus_warn ("did not expect unused bytes (scripts must specify explicitly if they are expected)\n");
370       goto out;
371     }
372
373   if (_dbus_string_get_length (&from_auth) > 0)
374     {
375       const char *s;
376       _dbus_warn ("script did not have EXPECT_ statements for all the data received from the DBusAuth\n");
377       _dbus_string_get_const_data (&from_auth, &s);
378       _dbus_warn ("Leftover data: %s\n", s);
379       goto out;
380     }
381   
382   retval = TRUE;
383   
384  out:
385   if (auth)
386     _dbus_auth_unref (auth);
387
388   _dbus_string_free (&file);
389   _dbus_string_free (&file);
390   _dbus_string_free (&from_auth);
391   
392   return retval;
393 }
394
395 /** @} */
396 #endif /* DBUS_BUILD_TESTS */