d954c8ddabf7ad9a72b81e67057c126e5a1852c6
[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 /* this is slightly different from the other append_quoted_string
46  * in dbus-message-builder.c
47  */
48 static dbus_bool_t
49 append_quoted_string (DBusString       *dest,
50                       const DBusString *quoted)
51 {
52   dbus_bool_t in_quotes = FALSE;
53   dbus_bool_t in_backslash = FALSE;
54   int i;
55
56   i = 0;
57   while (i < _dbus_string_get_length (quoted))
58     {
59       unsigned char b;
60
61       b = _dbus_string_get_byte (quoted, i);
62
63       if (in_backslash)
64         {
65           unsigned char a;
66           
67           if (b == 'r')
68             a = '\r';
69           else if (b == 'n')
70             a = '\n';
71           else if (b == '\\')
72             a = '\\';
73           else
74             {
75               _dbus_warn ("bad backslashed byte %c\n", b);
76               return FALSE;
77             }
78
79           if (!_dbus_string_append_byte (dest, a))
80             return FALSE;
81           
82           in_backslash = FALSE;
83         }
84       else if (b == '\\')
85         {
86           in_backslash = TRUE;
87         }
88       else if (in_quotes)
89         {
90           if (b == '\'')
91             in_quotes = FALSE;
92           else
93             {
94               if (!_dbus_string_append_byte (dest, b))
95                 return FALSE;
96             }
97         }
98       else
99         {
100           if (b == '\'')
101             in_quotes = TRUE;
102           else if (b == ' ' || b == '\n' || b == '\t')
103             break; /* end on whitespace if not quoted */
104           else
105             {
106               if (!_dbus_string_append_byte (dest, b))
107                 return FALSE;
108             }
109         }
110       
111       ++i;
112     }
113
114   return TRUE;
115 }
116
117 static dbus_bool_t
118 same_first_word (const DBusString *a,
119                  const DBusString *b)
120 {
121   int first_a_blank, first_b_blank;
122
123   _dbus_string_find_blank (a, 0, &first_a_blank);
124   _dbus_string_find_blank (b, 0, &first_b_blank);
125
126   if (first_a_blank != first_b_blank)
127     return FALSE;
128
129   return _dbus_string_equal_len (a, b, first_a_blank);
130 }
131
132 static DBusAuthState
133 auth_state_from_string (const DBusString *str)
134
135   if (_dbus_string_starts_with_c_str (str, "WAITING_FOR_INPUT"))
136     return DBUS_AUTH_STATE_WAITING_FOR_INPUT;
137   else if (_dbus_string_starts_with_c_str (str, "WAITING_FOR_MEMORY"))
138     return DBUS_AUTH_STATE_WAITING_FOR_MEMORY;
139   else if (_dbus_string_starts_with_c_str (str, "HAVE_BYTES_TO_SEND"))
140     return DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND;
141   else if (_dbus_string_starts_with_c_str (str, "NEED_DISCONNECT"))
142     return DBUS_AUTH_STATE_NEED_DISCONNECT;
143   else if (_dbus_string_starts_with_c_str (str, "AUTHENTICATED_WITH_UNUSED_BYTES"))
144     return DBUS_AUTH_STATE_AUTHENTICATED_WITH_UNUSED_BYTES;
145   else if (_dbus_string_starts_with_c_str (str, "AUTHENTICATED"))
146     return DBUS_AUTH_STATE_AUTHENTICATED;
147   else
148     return -1;
149 }
150
151 static const char*
152 auth_state_to_string (DBusAuthState state)
153 {
154   switch (state)
155     {
156     case DBUS_AUTH_STATE_WAITING_FOR_INPUT:
157       return "WAITING_FOR_INPUT";
158     case DBUS_AUTH_STATE_WAITING_FOR_MEMORY:
159       return "WAITING_FOR_MEMORY";
160     case DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND:
161       return "HAVE_BYTES_TO_SEND";
162     case DBUS_AUTH_STATE_NEED_DISCONNECT:
163       return "NEED_DISCONNECT";
164     case DBUS_AUTH_STATE_AUTHENTICATED_WITH_UNUSED_BYTES:
165       return "AUTHENTICATED_WITH_UNUSED_BYTES";
166     case DBUS_AUTH_STATE_AUTHENTICATED:
167       return "AUTHENTICATED";
168     }
169
170   return "unknown";
171 }
172
173 /**
174  * Runs an "auth script" which is a script for testing the
175  * authentication protocol. Scripts send and receive data, and then
176  * include assertions about the state of both ends of the connection
177  * after processing the data. A script succeeds if these assertions
178  * hold.
179  *
180  * @param filename the file containing the script to run
181  * @returns #TRUE if the script succeeds, #FALSE otherwise
182  */
183 dbus_bool_t
184 _dbus_auth_script_run (const DBusString *filename)
185 {
186   DBusString file;
187   DBusError error;
188   DBusString line;
189   dbus_bool_t retval;
190   int line_no;
191   DBusAuth *auth;
192   DBusString from_auth;
193   DBusAuthState state;
194   DBusString context;
195   
196   retval = FALSE;
197   auth = NULL;
198
199   _dbus_string_init_const (&context, "org_freedesktop_test");
200   
201   if (!_dbus_string_init (&file, _DBUS_INT_MAX))
202     return FALSE;
203
204   if (!_dbus_string_init (&line, _DBUS_INT_MAX))
205     {
206       _dbus_string_free (&file);
207       return FALSE;
208     }
209
210   if (!_dbus_string_init (&from_auth, _DBUS_INT_MAX))
211     {
212       _dbus_string_free (&file);
213       _dbus_string_free (&line);
214       return FALSE;
215     }
216
217   dbus_error_init (&error);
218   if (!_dbus_file_get_contents (&file, filename, &error))    {
219       const char *s;
220       _dbus_string_get_const_data (filename, &s);
221       _dbus_warn ("Getting contents of %s failed: %s\n",
222                   s, error.message);
223       dbus_error_free (&error);
224       goto out;
225     }
226
227   state = DBUS_AUTH_STATE_NEED_DISCONNECT;
228   line_no = 0;
229  next_iteration:
230   while (_dbus_string_pop_line (&file, &line))
231     {      
232       line_no += 1;
233
234       _dbus_string_delete_leading_blanks (&line);
235
236       if (auth != NULL)
237         {
238           while ((state = _dbus_auth_do_work (auth)) ==
239                  DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND)
240             {
241               const DBusString *tmp;
242               if (_dbus_auth_get_bytes_to_send (auth, &tmp))
243                 {
244                   int count = _dbus_string_get_length (tmp);
245
246                   if (_dbus_string_copy (tmp, 0, &from_auth,
247                                          _dbus_string_get_length (&from_auth)))
248                     _dbus_auth_bytes_sent (auth, count);
249                 }
250             }
251         }
252       
253       if (_dbus_string_get_length (&line) == 0)
254         {
255           /* empty line */
256           goto next_iteration;
257         }
258       else if (_dbus_string_starts_with_c_str (&line,
259                                                "#"))
260         {
261           /* Ignore this comment */
262           goto next_iteration;
263         }
264       else if (_dbus_string_starts_with_c_str (&line,
265                                                "CLIENT"))
266         {
267           DBusCredentials creds;
268           
269           if (auth != NULL)
270             {
271               _dbus_warn ("already created a DBusAuth (CLIENT or SERVER given twice)\n");
272               goto out;
273             }
274
275           auth = _dbus_auth_client_new ();
276           if (auth == NULL)
277             {
278               _dbus_warn ("no memory to create DBusAuth\n");
279               goto out;
280             }
281
282           _dbus_credentials_from_current_process (&creds);
283           _dbus_auth_set_credentials (auth, &creds);
284         }
285       else if (_dbus_string_starts_with_c_str (&line,
286                                                "SERVER"))
287         {
288           DBusCredentials creds;
289           
290           if (auth != NULL)
291             {
292               _dbus_warn ("already created a DBusAuth (CLIENT or SERVER given twice)\n");
293               goto out;
294             }
295
296           auth = _dbus_auth_server_new ();
297           if (auth == NULL)
298             {
299               _dbus_warn ("no memory to create DBusAuth\n");
300               goto out;
301             }
302
303           _dbus_credentials_from_current_process (&creds);
304           _dbus_auth_set_credentials (auth, &creds);
305           _dbus_auth_set_context (auth, &context);
306         }
307       else if (auth == NULL)
308         {
309           _dbus_warn ("must specify CLIENT or SERVER\n");
310           goto out;
311
312         }
313       else if (_dbus_string_starts_with_c_str (&line,
314                                                "NO_CREDENTIALS"))
315         {
316           DBusCredentials creds = { -1, -1, -1 };
317           _dbus_auth_set_credentials (auth, &creds);
318         }
319       else if (_dbus_string_starts_with_c_str (&line,
320                                                "ROOT_CREDENTIALS"))
321         {
322           DBusCredentials creds = { -1, 0, 0 };
323           _dbus_auth_set_credentials (auth, &creds);          
324         }
325       else if (_dbus_string_starts_with_c_str (&line,
326                                                "SILLY_CREDENTIALS"))
327         {
328           DBusCredentials creds = { -1, 4312, 1232 };
329           _dbus_auth_set_credentials (auth, &creds);          
330         }
331       else if (_dbus_string_starts_with_c_str (&line,
332                                                "SEND"))
333         {
334           DBusString to_send;
335           
336           _dbus_string_delete_first_word (&line);
337
338           if (!_dbus_string_init (&to_send, _DBUS_INT_MAX))
339             {
340               _dbus_warn ("no memory to allocate string\n");
341               goto out;
342             }
343
344           if (!append_quoted_string (&to_send, &line))
345             {
346               _dbus_warn ("failed to append quoted string line %d\n",
347                           line_no);
348               _dbus_string_free (&to_send);
349               goto out;
350             }
351
352           {
353             const char *s4;
354             _dbus_string_get_const_data (&to_send, &s4);
355             _dbus_verbose ("Sending '%s'\n", s4);
356           }
357           
358           if (!_dbus_string_append (&to_send, "\r\n"))
359             {
360               _dbus_warn ("failed to append \r\n from line %d\n",
361                           line_no);
362               _dbus_string_free (&to_send);
363               goto out;
364             }
365
366           /* Replace USERID_BASE64 with our username in base64 */
367           {
368             int where;
369             
370             if (_dbus_string_find (&to_send, 0,
371                                    "USERID_BASE64", &where))
372               {
373                 DBusString username;
374
375                 if (!_dbus_string_init (&username, _DBUS_INT_MAX))
376                   {
377                     _dbus_warn ("no memory for userid\n");
378                     _dbus_string_free (&to_send);
379                     goto out;
380                   }
381
382                 if (!_dbus_string_append_our_uid (&username))
383                   {
384                     _dbus_warn ("no memory for userid\n");
385                     _dbus_string_free (&username);
386                     _dbus_string_free (&to_send);
387                     goto out;
388                   }
389
390                 _dbus_string_delete (&to_send, where, strlen ("USERID_BASE64"));
391                 
392                 if (!_dbus_string_base64_encode (&username, 0,
393                                                  &to_send, where))
394                   {
395                     _dbus_warn ("no memory to subst USERID_BASE64\n");
396                     _dbus_string_free (&username);
397                     _dbus_string_free (&to_send);
398                     goto out;
399                   }
400
401                 _dbus_string_free (&username);
402               }
403             else if (_dbus_string_find (&to_send, 0,
404                                         "USERNAME_BASE64", &where))
405               {
406                 DBusString username;
407                 const DBusString *u;
408                 
409                 if (!_dbus_string_init (&username, _DBUS_INT_MAX))
410                   {
411                     _dbus_warn ("no memory for username\n");
412                     _dbus_string_free (&to_send);
413                     goto out;
414                   }
415
416                 if (!_dbus_user_info_from_current_process (&u, NULL, NULL) ||
417                     !_dbus_string_copy (u, 0, &username,
418                                         _dbus_string_get_length (&username)))
419                   {
420                     _dbus_warn ("no memory for username\n");
421                     _dbus_string_free (&username);
422                     _dbus_string_free (&to_send);
423                     goto out;
424                   }
425
426                 _dbus_string_delete (&to_send, where, strlen ("USERNAME_BASE64"));
427                 
428                 if (!_dbus_string_base64_encode (&username, 0,
429                                                  &to_send, where))
430                   {
431                     _dbus_warn ("no memory to subst USERNAME_BASE64\n");
432                     _dbus_string_free (&username);
433                     _dbus_string_free (&to_send);
434                     goto out;
435                   }
436
437                 _dbus_string_free (&username);
438               }
439           }
440
441           {
442             DBusString *buffer;
443
444             _dbus_auth_get_buffer (auth, &buffer);
445             if (!_dbus_string_copy (&to_send, 0,
446                                     buffer, _dbus_string_get_length (buffer)))
447               {
448                 _dbus_warn ("not enough memory to call bytes_received, or can't add bytes to auth object already in end state\n");
449                 _dbus_string_free (&to_send);
450                 _dbus_auth_return_buffer (auth, buffer, 0);
451                 goto out;
452               }
453
454             _dbus_auth_return_buffer (auth, buffer, _dbus_string_get_length (&to_send));
455           }
456           
457           _dbus_string_free (&to_send);
458         }
459       else if (_dbus_string_starts_with_c_str (&line,
460                                                "EXPECT_STATE"))
461         {
462           DBusAuthState expected;
463           
464           _dbus_string_delete_first_word (&line);
465
466           expected = auth_state_from_string (&line);
467           if (expected < 0)
468             {
469               _dbus_warn ("bad auth state given to EXPECT_STATE\n");
470               goto parse_failed;
471             }
472
473           if (expected != state)
474             {
475               _dbus_warn ("expected auth state %s but got %s on line %d\n",
476                           auth_state_to_string (expected),
477                           auth_state_to_string (state),
478                           line_no);
479               goto out;
480             }
481         }
482       else if (_dbus_string_starts_with_c_str (&line,
483                                                "EXPECT_COMMAND"))
484         {
485           DBusString received;
486           
487           _dbus_string_delete_first_word (&line);
488
489           if (!_dbus_string_init (&received, _DBUS_INT_MAX))
490             {
491               _dbus_warn ("no mem to allocate string received\n");
492               goto out;
493             }
494
495           if (!_dbus_string_pop_line (&from_auth, &received))
496             {
497               const char *command;
498               _dbus_string_get_const_data (&line, &command);
499               _dbus_warn ("no line popped from the DBusAuth being tested, expected command %s on line %d\n",
500                           command, line_no);
501               _dbus_string_free (&received);
502               goto out;
503             }
504
505           if (!same_first_word (&received, &line))
506             {
507               const char *s1, *s2;
508               _dbus_string_get_const_data (&line, &s1);
509               _dbus_string_get_const_data (&received, &s2);
510               _dbus_warn ("line %d expected command '%s' and got '%s'\n",
511                           line_no, s1, s2);
512               _dbus_string_free (&received);
513               goto out;
514             }
515           
516           _dbus_string_free (&received);
517         }
518       else if (_dbus_string_starts_with_c_str (&line,
519                                                "EXPECT_UNUSED"))
520         {
521           DBusString expected;
522           const DBusString *unused;
523           
524           _dbus_string_delete_first_word (&line);
525
526           if (!_dbus_string_init (&expected, _DBUS_INT_MAX))
527             {
528               _dbus_warn ("no mem to allocate string expected\n");
529               goto out;
530             }
531
532           if (!append_quoted_string (&expected, &line))
533             {
534               _dbus_warn ("failed to append quoted string line %d\n",
535                           line_no);
536               _dbus_string_free (&expected);
537               goto out;
538             }
539
540           _dbus_auth_get_unused_bytes (auth, &unused);
541           
542           if (_dbus_string_equal (&expected, unused))
543             {
544               _dbus_string_free (&expected);
545             }
546           else
547             {
548               const char *e1, *h1;
549               _dbus_string_get_const_data (&expected, &e1);
550               _dbus_string_get_const_data (unused, &h1);
551               _dbus_warn ("Expected unused bytes '%s' and have '%s'\n",
552                           e1, h1);
553               _dbus_string_free (&expected);
554               goto out;
555             }
556         }
557       else if (_dbus_string_starts_with_c_str (&line,
558                                                "EXPECT"))
559         {
560           DBusString expected;
561           
562           _dbus_string_delete_first_word (&line);
563
564           if (!_dbus_string_init (&expected, _DBUS_INT_MAX))
565             {
566               _dbus_warn ("no mem to allocate string expected\n");
567               goto out;
568             }
569
570           if (!append_quoted_string (&expected, &line))
571             {
572               _dbus_warn ("failed to append quoted string line %d\n",
573                           line_no);
574               _dbus_string_free (&expected);
575               goto out;
576             }
577
578           if (_dbus_string_equal_len (&expected, &from_auth,
579                                       _dbus_string_get_length (&expected)))
580             {
581               _dbus_string_delete (&from_auth, 0,
582                                    _dbus_string_get_length (&expected));
583               _dbus_string_free (&expected);
584             }
585           else
586             {
587               const char *e1, *h1;
588               _dbus_string_get_const_data (&expected, &e1);
589               _dbus_string_get_const_data (&from_auth, &h1);
590               _dbus_warn ("Expected exact string '%s' and have '%s'\n",
591                           e1, h1);
592               _dbus_string_free (&expected);
593               goto out;
594             }
595         }
596       else
597         goto parse_failed;
598
599       goto next_iteration; /* skip parse_failed */
600       
601     parse_failed:
602       {
603         const char *s;
604         _dbus_string_get_const_data (&line, &s);
605         _dbus_warn ("couldn't process line %d \"%s\"\n",
606                     line_no, s);
607         goto out;
608       }
609     }
610
611   if (auth != NULL &&
612       state == DBUS_AUTH_STATE_AUTHENTICATED_WITH_UNUSED_BYTES)
613     {
614       _dbus_warn ("did not expect unused bytes (scripts must specify explicitly if they are expected)\n");
615       goto out;
616     }
617
618   if (_dbus_string_get_length (&from_auth) > 0)
619     {
620       const char *s;
621       _dbus_warn ("script did not have EXPECT_ statements for all the data received from the DBusAuth\n");
622       _dbus_string_get_const_data (&from_auth, &s);
623       _dbus_warn ("Leftover data: %s\n", s);
624       goto out;
625     }
626   
627   retval = TRUE;
628   
629  out:
630   if (auth)
631     _dbus_auth_unref (auth);
632
633   _dbus_string_free (&file);
634   _dbus_string_free (&line);
635   _dbus_string_free (&from_auth);
636   
637   return retval;
638 }
639
640 /** @} */
641 #endif /* DBUS_BUILD_TESTS */