(linenum→info "unix/slp.c:2238")

dbus/1.0.2/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.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: #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-userdb.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"))
  144:     return DBUS_AUTH_STATE_AUTHENTICATED;
  145:   else
  146:     return -1;
  147: }
  148: 
  149: static const char*
  150: auth_state_to_string (DBusAuthState state)
  151: {
  152:   switch (state)
  153:     {
  154:     case DBUS_AUTH_STATE_WAITING_FOR_INPUT:
  155:       return "WAITING_FOR_INPUT";
  156:     case DBUS_AUTH_STATE_WAITING_FOR_MEMORY:
  157:       return "WAITING_FOR_MEMORY";
  158:     case DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND:
  159:       return "HAVE_BYTES_TO_SEND";
  160:     case DBUS_AUTH_STATE_NEED_DISCONNECT:
  161:       return "NEED_DISCONNECT";
  162:     case DBUS_AUTH_STATE_AUTHENTICATED:
  163:       return "AUTHENTICATED";
  164:     }
  165: 
  166:   return "unknown";
  167: }
  168: 
  169: static char **
  170: split_string (DBusString *str)
  171: {
  172:   int i, j, k, count, end;
  173:   char **array;
  174: 
  175:   end = _dbus_string_get_length (str);
  176: 
  177:   i = 0;
  178:   _dbus_string_skip_blank (str, i, &i);
  179:   for (count = 0; i < end; count++)
  180:     {
  181:       _dbus_string_find_blank (str, i, &i);
  182:       _dbus_string_skip_blank (str, i, &i);
  183:     }
  184: 
  185:   array = dbus_new0 (char *, count + 1);
  186:   if (array == NULL)
  187:     return NULL;
  188: 
  189:   i = 0;
  190:   _dbus_string_skip_blank (str, i, &i);
  191:   for (k = 0; k < count; k++)
  192:     {
  193:       _dbus_string_find_blank (str, i, &j);
  194: 
  195:       array[k] = dbus_malloc (j - i + 1);
  196:       if (array[k] == NULL)
  197:         {
  198:           dbus_free_string_array (array);
  199:           return NULL;
  200:         }
  201:       memcpy (array[k],
  202:               _dbus_string_get_const_data_len (str, i, j - i), j - i);
  203:       array[k][j - i] = '\0';
  204: 
  205:       _dbus_string_skip_blank (str, j, &i);
  206:     }
  207:   array[k] = NULL;
  208: 
  209:   return array;
  210: }
  211: 
  212: /**
  213:  * Runs an "auth script" which is a script for testing the
  214:  * authentication protocol. Scripts send and receive data, and then
  215:  * include assertions about the state of both ends of the connection
  216:  * after processing the data. A script succeeds if these assertions
  217:  * hold.
  218:  *
  219:  * @param filename the file containing the script to run
  220:  * @returns #TRUE if the script succeeds, #FALSE otherwise
  221:  */
  222: dbus_bool_t
  223: _dbus_auth_script_run (const DBusString *filename)
  224: {
  225:   DBusString file;
  226:   DBusError error;
  227:   DBusString line;
  228:   dbus_bool_t retval;
  229:   int line_no;
  230:   DBusAuth *auth;
  231:   DBusString from_auth;
  232:   DBusAuthState state;
  233:   DBusString context;
  234:   DBusString guid;
  235:   
  236:   retval = FALSE;
  237:   auth = NULL;
  238: 
  239:   _dbus_string_init_const (&guid, "5fa01f4202cd837709a3274ca0df9d00");
  240:   _dbus_string_init_const (&context, "org_freedesktop_test");
  241:   
  242:   if (!_dbus_string_init (&file))
  243:     return FALSE;
  244: 
  245:   if (!_dbus_string_init (&line))
  246:     {
  247:       _dbus_string_free (&file);
  248:       return FALSE;
  249:     }
  250: 
  251:   if (!_dbus_string_init (&from_auth))
  252:     {
  253:       _dbus_string_free (&file);
  254:       _dbus_string_free (&line);
  255:       return FALSE;
  256:     }
  257: 
  258:   dbus_error_init (&error);
  259:   if (!_dbus_file_get_contents (&file, filename, &error))    {
  260:       _dbus_warn ("Getting contents of %s failed: %s\n",
  261:                   _dbus_string_get_const_data (filename), error.message);
  262:       dbus_error_free (&error);
  263:       goto out;
  264:     }
  265: 
  266:   state = DBUS_AUTH_STATE_NEED_DISCONNECT;
  267:   line_no = 0;
  268:  next_iteration:
  269:   while (_dbus_string_pop_line (&file, &line))
  270:     {      
  271:       line_no += 1;
  272: 
  273:       _dbus_string_delete_leading_blanks (&line);
  274: 
  275:       if (auth != NULL)
  276:         {
  277:           while ((state = _dbus_auth_do_work (auth)) ==
  278:                  DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND)
  279:             {
  280:               const DBusString *tmp;
  281:               if (_dbus_auth_get_bytes_to_send (auth, &tmp))
  282:                 {
  283:                   int count = _dbus_string_get_length (tmp);
  284: 
  285:                   if (_dbus_string_copy (tmp, 0, &from_auth,
  286:                                          _dbus_string_get_length (&from_auth)))
  287:                     _dbus_auth_bytes_sent (auth, count);
  288:                 }
  289:             }
  290:         }
  291:       
  292:       if (_dbus_string_get_length (&line) == 0)
  293:         {
  294:           /* empty line */
  295:           goto next_iteration;
  296:         }
  297:       else if (_dbus_string_starts_with_c_str (&line,
  298:                                                "#"))
  299:         {
  300:           /* Ignore this comment */
  301:           goto next_iteration;
  302:         }
  303:       else if (_dbus_string_starts_with_c_str (&line,
  304:                                                "CLIENT"))
  305:         {
  306:           DBusCredentials creds;
  307:           
  308:           if (auth != NULL)
  309:             {
  310:               _dbus_warn ("already created a DBusAuth (CLIENT or SERVER given twice)\n");
  311:               goto out;
  312:             }
  313: 
  314:           auth = _dbus_auth_client_new ();
  315:           if (auth == NULL)
  316:             {
  317:               _dbus_warn ("no memory to create DBusAuth\n");
  318:               goto out;
  319:             }
  320: 
  321:           /* test ref/unref */
  322:           _dbus_auth_ref (auth);
  323:           _dbus_auth_unref (auth);
  324:           
  325:           _dbus_credentials_from_current_process (&creds);
  326:           _dbus_auth_set_credentials (auth, &creds);
  327:         }
  328:       else if (_dbus_string_starts_with_c_str (&line,
  329:                                                "SERVER"))
  330:         {
  331:           DBusCredentials creds;
  332:           
  333:           if (auth != NULL)
  334:             {
  335:               _dbus_warn ("already created a DBusAuth (CLIENT or SERVER given twice)\n");
  336:               goto out;
  337:             }
  338: 
  339:           auth = _dbus_auth_server_new (&guid);
  340:           if (auth == NULL)
  341:             {
  342:               _dbus_warn ("no memory to create DBusAuth\n");
  343:               goto out;
  344:             }
  345: 
  346:           /* test ref/unref */
  347:           _dbus_auth_ref (auth);
  348:           _dbus_auth_unref (auth);
  349:           
  350:           _dbus_credentials_from_current_process (&creds);
  351:           _dbus_auth_set_credentials (auth, &creds);
  352:           _dbus_auth_set_context (auth, &context);
  353:         }
  354:       else if (auth == NULL)
  355:         {
  356:           _dbus_warn ("must specify CLIENT or SERVER\n");
  357:           goto out;
  358: 
  359:         }
  360:       else if (_dbus_string_starts_with_c_str (&line,
  361:                                                "NO_CREDENTIALS"))
  362:         {
  363:           DBusCredentials creds = { -1, -1, -1 };
  364:           _dbus_auth_set_credentials (auth, &creds);
  365:         }
  366:       else if (_dbus_string_starts_with_c_str (&line,
  367:                                                "ROOT_CREDENTIALS"))
  368:         {
  369:           DBusCredentials creds = { -1, 0, 0 };
  370:           _dbus_auth_set_credentials (auth, &creds);          
  371:         }
  372:       else if (_dbus_string_starts_with_c_str (&line,
  373:                                                "SILLY_CREDENTIALS"))
  374:         {
  375:           DBusCredentials creds = { -1, 4312, 1232 };
  376:           _dbus_auth_set_credentials (auth, &creds);          
  377:         }
  378:       else if (_dbus_string_starts_with_c_str (&line,
  379:                                                "ALLOWED_MECHS"))
  380:         {
  381:           char **mechs;
  382: 
  383:           _dbus_string_delete_first_word (&line);
  384:           mechs = split_string (&line);
  385:           _dbus_auth_set_mechanisms (auth, (const char **) mechs);
  386:           dbus_free_string_array (mechs);
  387:         }
  388:       else if (_dbus_string_starts_with_c_str (&line,
  389:                                                "SEND"))
  390:         {
  391:           DBusString to_send;
  392:           
  393:           _dbus_string_delete_first_word (&line);
  394: 
  395:           if (!_dbus_string_init (&to_send))
  396:             {
  397:               _dbus_warn ("no memory to allocate string\n");
  398:               goto out;
  399:             }
  400: 
  401:           if (!append_quoted_string (&to_send, &line))
  402:             {
  403:               _dbus_warn ("failed to append quoted string line %d\n",
  404:                           line_no);
  405:               _dbus_string_free (&to_send);
  406:               goto out;
  407:             }
  408: 
  409:           _dbus_verbose ("Sending '%s'\n", _dbus_string_get_const_data (&to_send));
  410:           
  411:           if (!_dbus_string_append (&to_send, "\r\n"))
  412:             {
  413:               _dbus_warn ("failed to append \r\n from line %d\n",
  414:                           line_no);
  415:               _dbus_string_free (&to_send);
  416:               goto out;
  417:             }
  418: 
  419:           /* Replace USERID_HEX with our username in hex */
  420:           {
  421:             int where;
  422:             
  423:             if (_dbus_string_find (&to_send, 0,
  424:                                    "USERID_HEX", &where))
  425:               {
  426:                 DBusString username;
  427: 
  428:                 if (!_dbus_string_init (&username))
  429:                   {
  430:                     _dbus_warn ("no memory for userid\n");
  431:                     _dbus_string_free (&to_send);
  432:                     goto out;
  433:                   }
  434: 
  435:                 if (!_dbus_string_append_uint (&username,
  436:                                                _dbus_getuid ()))
  437:                   {
  438:                     _dbus_warn ("no memory for userid\n");
  439:                     _dbus_string_free (&username);
  440:                     _dbus_string_free (&to_send);
  441:                     goto out;
  442:                   }
  443: 
  444:                 _dbus_string_delete (&to_send, where, strlen ("USERID_HEX"));
  445:                 
  446:                 if (!_dbus_string_hex_encode (&username, 0,
  447:                                               &to_send, where))
  448:                   {
  449:                     _dbus_warn ("no memory to subst USERID_HEX\n");
  450:                     _dbus_string_free (&username);
  451:                     _dbus_string_free (&to_send);
  452:                     goto out;
  453:                   }
  454: 
  455:                 _dbus_string_free (&username);
  456:               }
  457:             else if (_dbus_string_find (&to_send, 0,
  458:                                         "USERNAME_HEX", &where))
  459:               {
  460:                 DBusString username;
  461:                 const DBusString *u;
  462:                 
  463:                 if (!_dbus_string_init (&username))
  464:                   {
  465:                     _dbus_warn ("no memory for username\n");
  466:                     _dbus_string_free (&to_send);
  467:                     goto out;
  468:                   }
  469: 
  470:                 if (!_dbus_username_from_current_process (&u) ||
  471:                     !_dbus_string_copy (u, 0, &username,
  472:                                         _dbus_string_get_length (&username)))
  473:                   {
  474:                     _dbus_warn ("no memory for username\n");
  475:                     _dbus_string_free (&username);
  476:                     _dbus_string_free (&to_send);
  477:                     goto out;
  478:                   }
  479: 
  480:                 _dbus_string_delete (&to_send, where, strlen ("USERNAME_HEX"));
  481:                 
  482:                 if (!_dbus_string_hex_encode (&username, 0,
  483:                                               &to_send, where))
  484:                   {
  485:                     _dbus_warn ("no memory to subst USERNAME_HEX\n");
  486:                     _dbus_string_free (&username);
  487:                     _dbus_string_free (&to_send);
  488:                     goto out;
  489:                   }
  490: 
  491:                 _dbus_string_free (&username);
  492:               }
  493:           }
  494: 
  495:           {
  496:             DBusString *buffer;
  497: 
  498:             _dbus_auth_get_buffer (auth, &buffer);
  499:             if (!_dbus_string_copy (&to_send, 0,
  500:                                     buffer, _dbus_string_get_length (buffer)))
  501:               {
  502:                 _dbus_warn ("not enough memory to call bytes_received, or can't add bytes to auth object already in end state\n");
  503:                 _dbus_string_free (&to_send);
  504:                 _dbus_auth_return_buffer (auth, buffer, 0);
  505:                 goto out;
  506:               }
  507: 
  508:             _dbus_auth_return_buffer (auth, buffer, _dbus_string_get_length (&to_send));
  509:           }
  510:           
  511:           _dbus_string_free (&to_send);
  512:         }
  513:       else if (_dbus_string_starts_with_c_str (&line,
  514:                                                "EXPECT_STATE"))
  515:         {
  516:           DBusAuthState expected;
  517:           
  518:           _dbus_string_delete_first_word (&line);
  519: 
  520:           expected = auth_state_from_string (&line);
  521:           if (expected < 0)
  522:             {
  523:               _dbus_warn ("bad auth state given to EXPECT_STATE\n");
  524:               goto parse_failed;
  525:             }
  526: 
  527:           if (expected != state)
  528:             {
  529:               _dbus_warn ("expected auth state %s but got %s on line %d\n",
  530:                           auth_state_to_string (expected),
  531:                           auth_state_to_string (state),
  532:                           line_no);
  533:               goto out;
  534:             }
  535:         }
  536:       else if (_dbus_string_starts_with_c_str (&line,
  537:                                                "EXPECT_COMMAND"))
  538:         {
  539:           DBusString received;
  540:           
  541:           _dbus_string_delete_first_word (&line);
  542: 
  543:           if (!_dbus_string_init (&received))
  544:             {
  545:               _dbus_warn ("no mem to allocate string received\n");
  546:               goto out;
  547:             }
  548: 
  549:           if (!_dbus_string_pop_line (&from_auth, &received))
  550:             {
  551:               _dbus_warn ("no line popped from the DBusAuth being tested, expected command %s on line %d\n",
  552:                           _dbus_string_get_const_data (&line), line_no);
  553:               _dbus_string_free (&received);
  554:               goto out;
  555:             }
  556: 
  557:           if (!same_first_word (&received, &line))
  558:             {
  559:               _dbus_warn ("line %d expected command '%s' and got '%s'\n",
  560:                           line_no,
  561:                           _dbus_string_get_const_data (&line),
  562:                           _dbus_string_get_const_data (&received));
  563:               _dbus_string_free (&received);
  564:               goto out;
  565:             }
  566:           
  567:           _dbus_string_free (&received);
  568:         }
  569:       else if (_dbus_string_starts_with_c_str (&line,
  570:                                                "EXPECT_UNUSED"))
  571:         {
  572:           DBusString expected;
  573:           const DBusString *unused;
  574:           
  575:           _dbus_string_delete_first_word (&line);
  576: 
  577:           if (!_dbus_string_init (&expected))
  578:             {
  579:               _dbus_warn ("no mem to allocate string expected\n");
  580:               goto out;
  581:             }
  582: 
  583:           if (!append_quoted_string (&expected, &line))
  584:             {
  585:               _dbus_warn ("failed to append quoted string line %d\n",
  586:                           line_no);
  587:               _dbus_string_free (&expected);
  588:               goto out;
  589:             }
  590: 
  591:           _dbus_auth_get_unused_bytes (auth, &unused);
  592:           
  593:           if (_dbus_string_equal (&expected, unused))
  594:             {
  595:               _dbus_auth_delete_unused_bytes (auth);
  596:               _dbus_string_free (&expected);
  597:             }
  598:           else
  599:             {
  600:               _dbus_warn ("Expected unused bytes '%s' and have '%s'\n",
  601:                           _dbus_string_get_const_data (&expected),