dbus-auth-script.c

00001 /* -*- mode: C; c-file-style: "gnu" -*- */
00002 /* dbus-auth-script.c Test DBusAuth using a special script file (internal to D-Bus implementation)
00003  * 
00004  * Copyright (C) 2003 Red Hat, Inc.
00005  *
00006  * Licensed under the Academic Free License version 2.1
00007  * 
00008  * This program is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * This program is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  * 
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, write to the Free Software
00020  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  *
00022  */
00023 #include <config.h>
00024 
00025 #ifdef DBUS_BUILD_TESTS
00026 
00027 #include "dbus-auth-script.h"
00028 #include "dbus-auth.h"
00029 #include "dbus-string.h"
00030 #include "dbus-hash.h"
00031 #include "dbus-internals.h"
00032 #include "dbus-userdb.h"
00033 
00045 /* this is slightly different from the other append_quoted_string
00046  * in dbus-message-builder.c
00047  */
00048 static dbus_bool_t
00049 append_quoted_string (DBusString       *dest,
00050                       const DBusString *quoted)
00051 {
00052   dbus_bool_t in_quotes = FALSE;
00053   dbus_bool_t in_backslash = FALSE;
00054   int i;
00055 
00056   i = 0;
00057   while (i < _dbus_string_get_length (quoted))
00058     {
00059       unsigned char b;
00060 
00061       b = _dbus_string_get_byte (quoted, i);
00062 
00063       if (in_backslash)
00064         {
00065           unsigned char a;
00066           
00067           if (b == 'r')
00068             a = '\r';
00069           else if (b == 'n')
00070             a = '\n';
00071           else if (b == '\\')
00072             a = '\\';
00073           else
00074             {
00075               _dbus_warn ("bad backslashed byte %c\n", b);
00076               return FALSE;
00077             }
00078 
00079           if (!_dbus_string_append_byte (dest, a))
00080             return FALSE;
00081           
00082           in_backslash = FALSE;
00083         }
00084       else if (b == '\\')
00085         {
00086           in_backslash = TRUE;
00087         }
00088       else if (in_quotes)
00089         {
00090           if (b == '\'')
00091             in_quotes = FALSE;
00092           else
00093             {
00094               if (!_dbus_string_append_byte (dest, b))
00095                 return FALSE;
00096             }
00097         }
00098       else
00099         {
00100           if (b == '\'')
00101             in_quotes = TRUE;
00102           else if (b == ' ' || b == '\n' || b == '\t')
00103             break; /* end on whitespace if not quoted */
00104           else
00105             {
00106               if (!_dbus_string_append_byte (dest, b))
00107                 return FALSE;
00108             }
00109         }
00110       
00111       ++i;
00112     }
00113 
00114   return TRUE;
00115 }
00116 
00117 static dbus_bool_t
00118 same_first_word (const DBusString *a,
00119                  const DBusString *b)
00120 {
00121   int first_a_blank, first_b_blank;
00122 
00123   _dbus_string_find_blank (a, 0, &first_a_blank);
00124   _dbus_string_find_blank (b, 0, &first_b_blank);
00125 
00126   if (first_a_blank != first_b_blank)
00127     return FALSE;
00128 
00129   return _dbus_string_equal_len (a, b, first_a_blank);
00130 }
00131 
00132 static DBusAuthState
00133 auth_state_from_string (const DBusString *str)
00134 { 
00135   if (_dbus_string_starts_with_c_str (str, "WAITING_FOR_INPUT"))
00136     return DBUS_AUTH_STATE_WAITING_FOR_INPUT;
00137   else if (_dbus_string_starts_with_c_str (str, "WAITING_FOR_MEMORY"))
00138     return DBUS_AUTH_STATE_WAITING_FOR_MEMORY;
00139   else if (_dbus_string_starts_with_c_str (str, "HAVE_BYTES_TO_SEND"))
00140     return DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND;
00141   else if (_dbus_string_starts_with_c_str (str, "NEED_DISCONNECT"))
00142     return DBUS_AUTH_STATE_NEED_DISCONNECT;
00143   else if (_dbus_string_starts_with_c_str (str, "AUTHENTICATED"))
00144     return DBUS_AUTH_STATE_AUTHENTICATED;
00145   else
00146     return -1;
00147 }
00148 
00149 static const char*
00150 auth_state_to_string (DBusAuthState state)
00151 {
00152   switch (state)
00153     {
00154     case DBUS_AUTH_STATE_WAITING_FOR_INPUT:
00155       return "WAITING_FOR_INPUT";
00156     case DBUS_AUTH_STATE_WAITING_FOR_MEMORY:
00157       return "WAITING_FOR_MEMORY";
00158     case DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND:
00159       return "HAVE_BYTES_TO_SEND";
00160     case DBUS_AUTH_STATE_NEED_DISCONNECT:
00161       return "NEED_DISCONNECT";
00162     case DBUS_AUTH_STATE_AUTHENTICATED:
00163       return "AUTHENTICATED";
00164     }
00165 
00166   return "unknown";
00167 }
00168 
00169 static char **
00170 split_string (DBusString *str)
00171 {
00172   int i, j, k, count, end;
00173   char **array;
00174 
00175   end = _dbus_string_get_length (str);
00176 
00177   i = 0;
00178   _dbus_string_skip_blank (str, i, &i);
00179   for (count = 0; i < end; count++)
00180     {
00181       _dbus_string_find_blank (str, i, &i);
00182       _dbus_string_skip_blank (str, i, &i);
00183     }
00184 
00185   array = dbus_new0 (char *, count + 1);
00186   if (array == NULL)
00187     return NULL;
00188 
00189   i = 0;
00190   _dbus_string_skip_blank (str, i, &i);
00191   for (k = 0; k < count; k++)
00192     {
00193       _dbus_string_find_blank (str, i, &j);
00194 
00195       array[k] = dbus_malloc (j - i + 1);
00196       if (array[k] == NULL)
00197         {
00198           dbus_free_string_array (array);
00199           return NULL;
00200         }
00201       memcpy (array[k],
00202               _dbus_string_get_const_data_len (str, i, j - i), j - i);
00203       array[k][j - i] = '\0';
00204 
00205       _dbus_string_skip_blank (str, j, &i);
00206     }
00207   array[k] = NULL;
00208 
00209   return array;
00210 }
00211 
00222 dbus_bool_t
00223 _dbus_auth_script_run (const DBusString *filename)
00224 {
00225   DBusString file;
00226   DBusError error;
00227   DBusString line;
00228   dbus_bool_t retval;
00229   int line_no;
00230   DBusAuth *auth;
00231   DBusString from_auth;
00232   DBusAuthState state;
00233   DBusString context;
00234   DBusString guid;
00235   
00236   retval = FALSE;
00237   auth = NULL;
00238 
00239   _dbus_string_init_const (&guid, "5fa01f4202cd837709a3274ca0df9d00");
00240   _dbus_string_init_const (&context, "org_freedesktop_test");
00241   
00242   if (!_dbus_string_init (&file))
00243     return FALSE;
00244 
00245   if (!_dbus_string_init (&line))
00246     {
00247       _dbus_string_free (&file);
00248       return FALSE;
00249     }
00250 
00251   if (!_dbus_string_init (&from_auth))
00252     {
00253       _dbus_string_free (&file);
00254       _dbus_string_free (&line);
00255       return FALSE;
00256     }
00257 
00258   dbus_error_init (&error);
00259   if (!_dbus_file_get_contents (&file, filename, &error))    {
00260       _dbus_warn ("Getting contents of %s failed: %s\n",
00261                   _dbus_string_get_const_data (filename), error.message);
00262       dbus_error_free (&error);
00263       goto out;
00264     }
00265 
00266   state = DBUS_AUTH_STATE_NEED_DISCONNECT;
00267   line_no = 0;
00268  next_iteration:
00269   while (_dbus_string_pop_line (&file, &line))
00270     {      
00271       line_no += 1;
00272 
00273       _dbus_string_delete_leading_blanks (&line);
00274 
00275       if (auth != NULL)
00276         {
00277           while ((state = _dbus_auth_do_work (auth)) ==
00278                  DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND)
00279             {
00280               const DBusString *tmp;
00281               if (_dbus_auth_get_bytes_to_send (auth, &tmp))
00282                 {
00283                   int count = _dbus_string_get_length (tmp);
00284 
00285                   if (_dbus_string_copy (tmp, 0, &from_auth,
00286                                          _dbus_string_get_length (&from_auth)))
00287                     _dbus_auth_bytes_sent (auth, count);
00288                 }
00289             }
00290         }
00291       
00292       if (_dbus_string_get_length (&line) == 0)
00293         {
00294           /* empty line */
00295           goto next_iteration;
00296         }
00297       else if (_dbus_string_starts_with_c_str (&line,
00298                                                "#"))
00299         {
00300           /* Ignore this comment */
00301           goto next_iteration;
00302         }
00303       else if (_dbus_string_starts_with_c_str (&line,
00304                                                "CLIENT"))
00305         {
00306           DBusCredentials creds;
00307           
00308           if (auth != NULL)
00309             {
00310               _dbus_warn ("already created a DBusAuth (CLIENT or SERVER given twice)\n");
00311               goto out;
00312             }
00313 
00314           auth = _dbus_auth_client_new ();
00315           if (auth == NULL)
00316             {
00317               _dbus_warn ("no memory to create DBusAuth\n");
00318               goto out;
00319             }
00320 
00321           /* test ref/unref */
00322           _dbus_auth_ref (auth);
00323           _dbus_auth_unref (auth);
00324           
00325           _dbus_credentials_from_current_process (&creds);
00326           _dbus_auth_set_credentials (auth, &creds);
00327         }
00328       else if (_dbus_string_starts_with_c_str (&line,
00329                                                "SERVER"))
00330         {
00331           DBusCredentials creds;
00332           
00333           if (auth != NULL)
00334             {
00335               _dbus_warn ("already created a DBusAuth (CLIENT or SERVER given twice)\n");
00336               goto out;
00337             }
00338 
00339           auth = _dbus_auth_server_new (&guid);
00340           if (auth == NULL)
00341             {
00342               _dbus_warn ("no memory to create DBusAuth\n");
00343               goto out;
00344             }
00345 
00346           /* test ref/unref */
00347           _dbus_auth_ref (auth);
00348           _dbus_auth_unref (auth);
00349           
00350           _dbus_credentials_from_current_process (&creds);
00351           _dbus_auth_set_credentials (auth, &creds);
00352           _dbus_auth_set_context (auth, &context);
00353         }
00354       else if (auth == NULL)
00355         {
00356           _dbus_warn ("must specify CLIENT or SERVER\n");
00357           goto out;
00358 
00359         }
00360       else if (_dbus_string_starts_with_c_str (&line,
00361                                                "NO_CREDENTIALS"))
00362         {
00363           DBusCredentials creds = { -1, -1, -1 };
00364           _dbus_auth_set_credentials (auth, &creds);
00365         }
00366       else if (_dbus_string_starts_with_c_str (&line,
00367                                                "ROOT_CREDENTIALS"))
00368         {
00369           DBusCredentials creds = { -1, 0, 0 };
00370           _dbus_auth_set_credentials (auth, &creds);          
00371         }
00372       else if (_dbus_string_starts_with_c_str (&line,
00373                                                "SILLY_CREDENTIALS"))
00374         {
00375           DBusCredentials creds = { -1, 4312, 1232 };
00376           _dbus_auth_set_credentials (auth, &creds);          
00377         }
00378       else if (_dbus_string_starts_with_c_str (&line,
00379                                                "ALLOWED_MECHS"))
00380         {
00381           char **mechs;
00382 
00383           _dbus_string_delete_first_word (&line);
00384           mechs = split_string (&line);
00385           _dbus_auth_set_mechanisms (auth, (const char **) mechs);
00386           dbus_free_string_array (mechs);
00387         }
00388       else if (_dbus_string_starts_with_c_str (&line,
00389                                                "SEND"))
00390         {
00391           DBusString to_send;
00392           
00393           _dbus_string_delete_first_word (&line);
00394 
00395           if (!_dbus_string_init (&to_send))
00396             {
00397               _dbus_warn ("no memory to allocate string\n");
00398               goto out;
00399             }
00400 
00401           if (!append_quoted_string (&to_send, &line))
00402             {
00403               _dbus_warn ("failed to append quoted string line %d\n",
00404                           line_no);
00405               _dbus_string_free (&to_send);
00406               goto out;
00407             }
00408 
00409           _dbus_verbose ("Sending '%s'\n", _dbus_string_get_const_data (&to_send));
00410           
00411           if (!_dbus_string_append (&to_send, "\r\n"))
00412             {
00413               _dbus_warn ("failed to append \r\n from line %d\n",
00414                           line_no);
00415               _dbus_string_free (&to_send);
00416               goto out;
00417             }
00418 
00419           /* Replace USERID_HEX with our username in hex */
00420           {
00421             int where;
00422             
00423             if (_dbus_string_find (&to_send, 0,
00424                                    "USERID_HEX", &where))
00425               {
00426                 DBusString username;
00427 
00428                 if (!_dbus_string_init (&username))
00429                   {
00430                     _dbus_warn ("no memory for userid\n");
00431                     _dbus_string_free (&to_send);
00432                     goto out;
00433                   }
00434 
00435                 if (!_dbus_string_append_uint (&username,
00436                                                _dbus_getuid ()))
00437                   {
00438                     _dbus_warn ("no memory for userid\n");
00439                     _dbus_string_free (&username);
00440                     _dbus_string_free (&to_send);
00441                     goto out;
00442                   }
00443 
00444                 _dbus_string_delete (&to_send, where, strlen ("USERID_HEX"));
00445                 
00446                 if (!_dbus_string_hex_encode (&username, 0,
00447                                               &to_send, where))
00448                   {
00449                     _dbus_warn ("no memory to subst USERID_HEX\n");
00450                     _dbus_string_free (&username);
00451                     _dbus_string_free (&to_send);
00452                     goto out;
00453                   }
00454 
00455                 _dbus_string_free (&username);
00456               }
00457             else if (_dbus_string_find (&to_send, 0,
00458                                         "USERNAME_HEX", &where))
00459               {
00460                 DBusString username;
00461                 const DBusString *u;
00462                 
00463                 if (!_dbus_string_init (&username))
00464                   {
00465                     _dbus_warn ("no memory for username\n");
00466                     _dbus_string_free (&to_send);
00467                     goto out;
00468                   }
00469 
00470                 if (!_dbus_username_from_current_process (&u) ||
00471                     !_dbus_string_copy (u, 0, &username,
00472                                         _dbus_string_get_length (&username)))
00473                   {
00474                     _dbus_warn ("no memory for username\n");
00475                     _dbus_string_free (&username);
00476                     _dbus_string_free (&to_send);
00477                     goto out;
00478                   }
00479 
00480                 _dbus_string_delete (&to_send, where, strlen ("USERNAME_HEX"));
00481                 
00482                 if (!_dbus_string_hex_encode (&username, 0,
00483                                               &to_send, where))
00484                   {
00485                     _dbus_warn ("no memory to subst USERNAME_HEX\n");
00486                     _dbus_string_free (&username);
00487                     _dbus_string_free (&to_send);
00488                     goto out;
00489                   }
00490 
00491                 _dbus_string_free (&username);
00492               }
00493           }
00494 
00495           {
00496             DBusString *buffer;
00497 
00498             _dbus_auth_get_buffer (auth, &buffer);
00499             if (!_dbus_string_copy (&to_send, 0,
00500                                     buffer, _dbus_string_get_length (buffer)))
00501               {
00502                 _dbus_warn ("not enough memory to call bytes_received, or can't add bytes to auth object already in end state\n");
00503                 _dbus_string_free (&to_send);
00504                 _dbus_auth_return_buffer (auth, buffer, 0);
00505                 goto out;
00506               }
00507 
00508             _dbus_auth_return_buffer (auth, buffer, _dbus_string_get_length (&to_send));
00509           }
00510           
00511           _dbus_string_free (&to_send);
00512         }
00513       else if (_dbus_string_starts_with_c_str (&line,
00514                                                "EXPECT_STATE"))
00515         {
00516           DBusAuthState expected;
00517           
00518           _dbus_string_delete_first_word (&line);
00519 
00520           expected = auth_state_from_string (&line);
00521           if (expected < 0)
00522             {
00523               _dbus_warn ("bad auth state given to EXPECT_STATE\n");
00524               goto parse_failed;
00525             }
00526 
00527           if (expected != state)
00528             {
00529               _dbus_warn ("expected auth state %s but got %s on line %d\n",
00530                           auth_state_to_string (expected),
00531                           auth_state_to_string (state),
00532                           line_no);
00533               goto out;
00534             }
00535         }
00536       else if (_dbus_string_starts_with_c_str (&line,
00537                                                "EXPECT_COMMAND"))
00538         {
00539           DBusString received;
00540           
00541           _dbus_string_delete_first_word (&line);
00542 
00543           if (!_dbus_string_init (&received))
00544             {
00545               _dbus_warn ("no mem to allocate string received\n");
00546               goto out;
00547             }
00548 
00549           if (!_dbus_string_pop_line (&from_auth, &received))
00550             {
00551               _dbus_warn ("no line popped from the DBusAuth being tested, expected command %s on line %d\n",
00552                           _dbus_string_get_const_data (&line), line_no);
00553               _dbus_string_free (&received);
00554               goto out;
00555             }
00556 
00557           if (!same_first_word (&received, &line))
00558             {
00559               _dbus_warn ("line %d expected command '%s' and got '%s'\n",
00560                           line_no,
00561                           _dbus_string_get_const_data (&line),
00562                           _dbus_string_get_const_data (&received));
00563               _dbus_string_free (&received);
00564               goto out;
00565             }
00566           
00567           _dbus_string_free (&received);
00568         }
00569       else if (_dbus_string_starts_with_c_str (&line,
00570                                                "EXPECT_UNUSED"))
00571         {
00572           DBusString expected;
00573           const DBusString *unused;
00574           
00575           _dbus_string_delete_first_word (&line);
00576 
00577           if (!_dbus_string_init (&expected))
00578             {
00579               _dbus_warn ("no mem to allocate string expected\n");
00580               goto out;
00581             }
00582 
00583           if (!append_quoted_string (&expected, &line))
00584             {
00585               _dbus_warn ("failed to append quoted string line %d\n",
00586                           line_no);
00587               _dbus_string_free (&expected);
00588               goto out;
00589             }
00590 
00591           _dbus_auth_get_unused_bytes (auth, &unused);
00592           
00593           if (_dbus_string_equal (&expected, unused))
00594             {
00595               _dbus_auth_delete_unused_bytes (auth);
00596               _dbus_string_free (&expected);
00597             }
00598           else
00599             {
00600               _dbus_warn ("Expected unused bytes '%s' and have '%s'\n",
00601                           _dbus_string_get_const_data (&expected),
00602                           _dbus_string_get_const_data (unused));
00603               _dbus_string_free (&expected);
00604               goto out;
00605             }
00606         }
00607       else if (_dbus_string_starts_with_c_str (&line,
00608                                                "EXPECT"))
00609         {
00610           DBusString expected;
00611           
00612           _dbus_string_delete_first_word (&line);
00613 
00614           if (!_dbus_string_init (&expected))
00615             {
00616               _dbus_warn ("no mem to allocate string expected\n");
00617               goto out;
00618             }
00619 
00620           if (!append_quoted_string (&expected, &line))
00621             {
00622               _dbus_warn ("failed to append quoted string line %d\n",
00623                           line_no);
00624               _dbus_string_free (&expected);
00625               goto out;
00626             }
00627 
00628           if (_dbus_string_equal_len (&expected, &from_auth,
00629                                       _dbus_string_get_length (&expected)))
00630             {
00631               _dbus_string_delete (&from_auth, 0,
00632                                    _dbus_string_get_length (&expected));
00633               _dbus_string_free (&expected);
00634             }
00635           else
00636             {
00637               _dbus_warn ("Expected exact string '%s' and have '%s'\n",
00638                           _dbus_string_get_const_data (&expected),
00639                           _dbus_string_get_const_data (&from_auth));
00640               _dbus_string_free (&expected);
00641               goto out;
00642             }
00643         }
00644       else
00645         goto parse_failed;
00646 
00647       goto next_iteration; /* skip parse_failed */
00648       
00649     parse_failed:
00650       {
00651         _dbus_warn ("couldn't process line %d \"%s\"\n",
00652                     line_no, _dbus_string_get_const_data (&line));
00653         goto out;
00654       }
00655     }
00656 
00657   if (auth != NULL &&
00658       state == DBUS_AUTH_STATE_AUTHENTICATED)
00659     {
00660       const DBusString *unused;
00661 
00662       _dbus_auth_get_unused_bytes (auth, &unused);
00663 
00664       if (_dbus_string_get_length (unused) > 0)
00665         {
00666           _dbus_warn ("did not expect unused bytes (scripts must specify explicitly if they are expected)\n");
00667           goto out;
00668         }
00669     }
00670 
00671   if (_dbus_string_get_length (&from_auth) > 0)
00672     {
00673       _dbus_warn ("script did not have EXPECT_ statements for all the data received from the DBusAuth\n");
00674       _dbus_warn ("Leftover data: %s\n", _dbus_string_get_const_data (&from_auth));
00675       goto out;
00676     }
00677   
00678   retval = TRUE;
00679   
00680  out:
00681   if (auth)
00682     _dbus_auth_unref (auth);
00683 
00684   _dbus_string_free (&file);
00685   _dbus_string_free (&line);
00686   _dbus_string_free (&from_auth);
00687   
00688   return retval;
00689 }
00690 
00692 #endif /* DBUS_BUILD_TESTS */

Generated on Tue Apr 15 15:53:54 2008 for D-Bus by  doxygen 1.5.1