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