浏览代码

getting somewhere

David Rose 16 年之前
父节点
当前提交
54c3e34f6e

+ 2 - 0
direct/src/plugin/Sources.pp

@@ -25,6 +25,7 @@
     p3d_lock.h p3d_plugin.h \
     p3d_plugin_config.h \
     p3d_plugin_common.h \
+    p3dAuthSession.h p3dAuthSession.I \
     p3dBoolObject.h \
     p3dConcreteSequence.h \
     p3dConcreteStruct.h \
@@ -57,6 +58,7 @@
 
   #define INCLUDED_SOURCES \
     p3d_plugin.cxx \
+    p3dAuthSession.cxx \
     p3dBoolObject.cxx \
     p3dConcreteSequence.cxx \
     p3dConcreteStruct.cxx \

+ 176 - 19
direct/src/plugin/p3dCert.cxx

@@ -14,6 +14,7 @@
 
 #include "p3dCert.h"
 #include "wx/cmdline.h"
+#include "wx/filename.h"
          
 #ifdef __WXMAC__
 #include <Carbon/Carbon.h>
@@ -85,6 +86,7 @@ IMPLEMENT_APP(P3DCertApp)
 ////////////////////////////////////////////////////////////////////
 bool P3DCertApp::
 OnInit() {
+  cerr << "OnInit\n";
   // call the base class initialization method, currently it only parses a
   // few common command-line options but it could be do more in the future
   if (!wxApp::OnInit()) {
@@ -103,8 +105,9 @@ OnInit() {
   SetFrontProcess(&psn);
 #endif
 
-  AuthDialog *dialog = new AuthDialog(_cert_filename, _ca_filename);
+  AuthDialog *dialog = new AuthDialog(_cert_filename, _cert_dir);
   SetTopWindow(dialog);
+  cerr << "got dialog " << dialog << "\n";
   dialog->Show(true);
 
   // Return true to enter the main loop and wait for user input.
@@ -132,7 +135,7 @@ OnInitCmdLine(wxCmdLineParser &parser) {
 bool P3DCertApp::
 OnCmdLineParsed(wxCmdLineParser &parser) {
   _cert_filename = parser.GetParam(0);
-  _ca_filename = parser.GetParam(1);
+  _cert_dir = parser.GetParam(1);
   return true;
 }
 
@@ -151,16 +154,19 @@ END_EVENT_TABLE()
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 AuthDialog::
-AuthDialog(const wxString &cert_filename, const wxString &ca_filename) : 
-  wxDialog(NULL, wxID_ANY, _T("New Panda3D Application"), wxDefaultPosition)
+AuthDialog(const wxString &cert_filename, const wxString &cert_dir) : 
+  wxDialog(NULL, wxID_ANY, _T("New Panda3D Application"), wxDefaultPosition),
+  _cert_dir(cert_dir)
 {
+  _view_cert_dialog = NULL;
+
   _cert = NULL;
   _stack = NULL;
   _verify_result = -1;
 
   read_cert_file(cert_filename);
   get_common_name();
-  verify_cert(ca_filename);
+  verify_cert();
   layout();
 }
 
@@ -171,6 +177,10 @@ AuthDialog(const wxString &cert_filename, const wxString &ca_filename) :
 ////////////////////////////////////////////////////////////////////
 AuthDialog::
 ~AuthDialog() {
+  if (_view_cert_dialog != NULL) {
+    _view_cert_dialog->Destroy();
+  }
+
   if (_cert != NULL) { 
     X509_free(_cert);
     _cert = NULL;
@@ -189,7 +199,7 @@ AuthDialog::
 void AuthDialog::
 run_clicked(wxCommandEvent &event) {
   cerr << "run\n";
-  Destroy();
+  approve_cert();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -200,6 +210,11 @@ run_clicked(wxCommandEvent &event) {
 void AuthDialog::
 view_cert_clicked(wxCommandEvent &event) {
   cerr << "view cert\n";
+  if (_view_cert_dialog != NULL) {
+    _view_cert_dialog->Destroy();
+  }
+  _view_cert_dialog = new ViewCertDialog(this, _cert);
+  _view_cert_dialog->Show();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -213,6 +228,41 @@ cancel_clicked(wxCommandEvent &event) {
   Destroy();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: AuthDialog::approve_cert
+//       Access: Public
+//  Description: Writes the certificate into the _cert_dir, so
+//               that it will be found by the P3DInstanceManager and
+//               known to be approved.
+////////////////////////////////////////////////////////////////////
+void AuthDialog::
+approve_cert() {
+  assert(_cert != NULL);
+
+  // Make sure the directory exists.
+  wxFileName::Mkdir(_cert_dir, 0777, wxPATH_MKDIR_FULL);
+
+  // Look for an unused filename.
+  wxString pathname;
+  int i = 1;
+  while (true) {
+    pathname.Printf(wxT("%s/p%d.crt"), _cert_dir.c_str(), i);
+    if (!wxFileName::FileExists(pathname)) {
+      break;
+    }
+    ++i;
+  }
+
+  // Sure, there's a slight race condition right now: another process
+  // might attempt to create the same filename.  So what.
+  FILE *fp = fopen(pathname.mb_str(), "w");
+  if (fp != NULL) {
+    PEM_write_X509(fp, _cert);
+    fclose(fp);
+  }
+  Destroy();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: AuthDialog::read_cert_file
 //       Access: Private
@@ -246,7 +296,7 @@ read_cert_file(const wxString &cert_filename) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: AuthDialog::get_common_name
-//       Access: Public
+//       Access: Private
 //  Description: Extracts the common_name from the certificate.
 ////////////////////////////////////////////////////////////////////
 void AuthDialog::
@@ -286,12 +336,12 @@ get_common_name() {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: AuthDialog::verify_cert
-//       Access: Public
+//       Access: Private
 //  Description: Checks whether the certificate is valid by the chain
 //               and initializes _verify_status accordingly.
 ////////////////////////////////////////////////////////////////////
 void AuthDialog::
-verify_cert(const wxString &ca_filename) {
+verify_cert() {
   if (_cert == NULL) {
     _verify_result = -1;
     return;
@@ -301,17 +351,25 @@ verify_cert(const wxString &ca_filename) {
   X509_STORE *store = X509_STORE_new();
   X509_STORE_set_default_paths(store);
 
-  // Read the trusted certificates.
-  FILE *fp = fopen(ca_filename.mb_str(), "r");
-  if (fp == NULL) {
-    cerr << "Couldn't read " << ca_filename << "\n";
-  } else {
-    X509 *c = PEM_read_X509(fp, NULL, NULL, (void *)"");
-    while (c != NULL) {
-      X509_STORE_add_cert(store, c);
-      c = PEM_read_X509(fp, NULL, NULL, (void *)"");
+  // Find the ca-bundle.crt.
+  char *p3dcert_root = getenv("P3DCERT_ROOT");
+  if (p3dcert_root != NULL) {
+    wxString ca_filename = p3dcert_root;
+    ca_filename += "/ca-bundle.crt";
+    
+    // Read the trusted certificates.
+    cerr << "Reading " << ca_filename.mb_str() << "\n";;
+    FILE *fp = fopen(ca_filename.mb_str(), "r");
+    if (fp == NULL) {
+      cerr << "Couldn't read " << ca_filename.mb_str() << "\n";
+    } else {
+      X509 *c = PEM_read_X509(fp, NULL, NULL, (void *)"");
+      while (c != NULL) {
+        X509_STORE_add_cert(store, c);
+        c = PEM_read_X509(fp, NULL, NULL, (void *)"");
+      }
+      fclose(fp);
     }
-    fclose(fp);
   }
 
   // Create the X509_STORE_CTX for verifying the cert and chain.
@@ -430,3 +488,102 @@ get_text(wxString &header, wxString &text) {
     text.Printf(generic_error_cert_text, _verify_result);
   }
 }
+
+
+// The event table for ViewCertDialog.
+BEGIN_EVENT_TABLE(ViewCertDialog, wxDialog)
+    EVT_BUTTON(wxID_OK, ViewCertDialog::run_clicked)
+    EVT_BUTTON(wxID_CANCEL, ViewCertDialog::cancel_clicked)
+END_EVENT_TABLE()
+
+////////////////////////////////////////////////////////////////////
+//     Function: ViewCertDialog::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+ViewCertDialog::
+ViewCertDialog(AuthDialog *auth_dialog, X509 *cert) :
+  wxDialog(NULL, wxID_ANY, _T("View Certificate"), wxDefaultPosition),
+  _auth_dialog(auth_dialog),
+  _cert(cert)
+{
+  layout();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ViewCertDialog::Destructor
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+ViewCertDialog::
+~ViewCertDialog() {
+  if (_auth_dialog != NULL) {
+    _auth_dialog->_view_cert_dialog = NULL;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ViewCertDialog::run_clicked
+//       Access: Public
+//  Description: The user clicks the "Run" button.
+////////////////////////////////////////////////////////////////////
+void ViewCertDialog::
+run_clicked(wxCommandEvent &event) {
+  cerr << "run\n";
+  if (_auth_dialog != NULL){ 
+    _auth_dialog->approve_cert();
+  }
+  Destroy();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ViewCertDialog::run_clicked
+//       Access: Public
+//  Description: The user clicks the "Cancel" button.
+////////////////////////////////////////////////////////////////////
+void ViewCertDialog::
+cancel_clicked(wxCommandEvent &event) {
+  cerr << "cancel\n";
+  Destroy();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ViewCertDialog::layout
+//       Access: Private
+//  Description: Arranges the text and controls within the dialog.
+////////////////////////////////////////////////////////////////////
+void ViewCertDialog::
+layout() {
+  // Format the certificate text for display in the dialog.
+  assert(_cert != NULL);
+
+  BIO *mbio = BIO_new(BIO_s_mem());
+  X509_print(mbio, _cert);
+
+  char *pp;
+  long pp_size = BIO_get_mem_data(mbio, &pp);
+  wxString cert_body(pp, wxConvUTF8, pp_size);
+  BIO_free(mbio);
+
+  wxPanel *panel = new wxPanel(this);
+  wxBoxSizer *vsizer = new wxBoxSizer(wxVERTICAL);
+
+  wxStaticText *text1 = new wxStaticText
+    (panel, wxID_ANY, cert_body, wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
+  vsizer->Add(text1, 0, wxCENTER | wxALL, 10);
+
+  // Create the run / cancel buttons.
+  wxBoxSizer *bsizer = new wxBoxSizer(wxHORIZONTAL);
+
+  wxButton *run_button = new wxButton(panel, wxID_OK, _T("Run"));
+  bsizer->Add(run_button, 0, wxALIGN_CENTER | wxALL, 5);
+
+  wxButton *cancel_button = new wxButton(panel, wxID_CANCEL, _T("Cancel"));
+  bsizer->Add(cancel_button, 0, wxALIGN_CENTER | wxALL, 5);
+
+  vsizer->Add(bsizer, 0, wxALIGN_CENTER | wxALL, 5);
+
+  panel->SetSizer(vsizer);
+  panel->SetAutoLayout(true);
+  vsizer->Fit(this);
+}

+ 34 - 3
direct/src/plugin/p3dCert.h

@@ -27,6 +27,8 @@
 #include <stdio.h>
 using namespace std;
 
+class ViewCertDialog;
+
 ////////////////////////////////////////////////////////////////////
 //       Class : P3DCertApp
 // Description : This is the wxApp that drives this application.
@@ -39,7 +41,7 @@ public:
 
 private:
   wxString _cert_filename;
-  wxString _ca_filename;
+  wxString _cert_dir;
 };
 
 ////////////////////////////////////////////////////////////////////
@@ -54,25 +56,31 @@ private:
 ////////////////////////////////////////////////////////////////////
 class AuthDialog : public wxDialog {
 public:
-  AuthDialog(const wxString &cert_filename, const wxString &ca_filename);
+  AuthDialog(const wxString &cert_filename, const wxString &cert_dir);
   virtual ~AuthDialog();
 
   void run_clicked(wxCommandEvent &event);
   void view_cert_clicked(wxCommandEvent &event);
   void cancel_clicked(wxCommandEvent &event);
 
+  void approve_cert();
+
 private:
   void read_cert_file(const wxString &cert_filename);
   void get_common_name();
-  void verify_cert(const wxString &ca_filename);
+  void verify_cert();
 
   void layout();
   void get_text(wxString &header, wxString &text);
 
+public:
+  ViewCertDialog *_view_cert_dialog;
+
 private:
   // any class wishing to process wxWidgets events must use this macro
   DECLARE_EVENT_TABLE()
 
+  wxString _cert_dir;
   X509 *_cert;
   STACK *_stack;
 
@@ -80,4 +88,27 @@ private:
   int _verify_result;
 };
 
+////////////////////////////////////////////////////////////////////
+//       Class : ViewCertDialog
+// Description : This is the detailed view of the particular
+//               certificate.
+////////////////////////////////////////////////////////////////////
+class ViewCertDialog : public wxDialog {
+public:
+  ViewCertDialog(AuthDialog *auth_dialog, X509 *cert);
+  virtual ~ViewCertDialog();
+
+  void run_clicked(wxCommandEvent &event);
+  void cancel_clicked(wxCommandEvent &event);
+
+private:
+  void layout();
+
+private:
+  DECLARE_EVENT_TABLE()
+
+  AuthDialog *_auth_dialog;
+  X509 *_cert;
+};
+
 #endif

+ 135 - 18
direct/src/plugin/p3dInstance.cxx

@@ -85,6 +85,7 @@ P3DInstance(P3D_request_ready_func *func,
   _got_fparams = false;
   _got_wparams = false;
   _p3d_trusted = false;
+  _p3dcert_package = NULL;
 
   _fparams.set_tokens(tokens, num_tokens);
   _fparams.set_args(argc, argv);
@@ -96,6 +97,7 @@ P3DInstance(P3D_request_ready_func *func,
   _auto_start = false;
   _auth_button_approved = false;
   _session = NULL;
+  _auth_session = NULL;
   _panda3d = NULL;
   _splash_window = NULL;
   _instance_window_opened = false;
@@ -140,6 +142,12 @@ P3DInstance::
 ~P3DInstance() {
   assert(_session == NULL);
 
+  if (_auth_session != NULL) {
+    _auth_session->shutdown(false);
+    unref_delete(_auth_session);
+    _auth_session = NULL;
+  }
+
   P3D_OBJECT_XDECREF(_browser_script_object);
 
   nout << "panda_script_object ref = "
@@ -159,6 +167,11 @@ P3DInstance::
     _image_package = NULL;
   }
 
+  if (_p3dcert_package != NULL) {
+    _p3dcert_package->remove_instance(this);
+    _p3dcert_package = NULL;
+  }
+
   if (_splash_window != NULL) {
     delete _splash_window;
     _splash_window = NULL;
@@ -929,20 +942,18 @@ splash_button_clicked_main_thread() {
 ////////////////////////////////////////////////////////////////////
 void P3DInstance::
 auth_button_clicked() {
-  // Here's where we need to invoke the authorization program.
   cerr << "auth clicked\n";
 
-  // After the authorization program has returned, check the signature
-  // again.
-  if (check_p3d_signature()) {
-    // Set this flag to indicate that the user has clicked on the red
-    // "auth" button an successfully approved the application.  This
-    // eliminates the need to click on the green "start" button.
-    _auth_button_approved = true;
-    mark_p3d_trusted();
-  } else {
-    mark_p3d_untrusted();
+  // Delete the previous session and create a new one.
+  if (_auth_session != NULL) {
+    _auth_session->shutdown(false);
+    unref_delete(_auth_session);
+    _auth_session = NULL;
   }
+  
+  P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
+  _auth_session = inst_mgr->authorize_instance(this);
+  _auth_session->ref();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -962,6 +973,49 @@ play_button_clicked() {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DInstance::auth_finished_sub_thread
+//       Access: Public
+//  Description: Called by the P3DAuthSession code in a sub-thread
+//               when the auth dialog exits (for instance, because the
+//               user approved the certificate, or cancelled).
+////////////////////////////////////////////////////////////////////
+void P3DInstance::
+auth_finished_sub_thread() {
+  TiXmlDocument *doc = new TiXmlDocument;
+  TiXmlElement *xrequest = new TiXmlElement("request");
+  xrequest->SetAttribute("rtype", "notify");
+  xrequest->SetAttribute("message", "authfinished");
+  doc->LinkEndChild(xrequest);
+
+  add_raw_request(doc);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DInstance::auth_finished_main_thread
+//       Access: Public
+//  Description: Called only in the main thread, indirectly from
+//               auth_finished_sub_thread(), as the result of
+//               the user closing the auth dialog.
+////////////////////////////////////////////////////////////////////
+void P3DInstance::
+auth_finished_main_thread() {
+  // After the authorization program has returned, check the signature
+  // again.
+  if (check_p3d_signature()) {
+    // Set this flag to indicate that the user has clicked on the red
+    // "auth" button and successfully approved the application's
+    // certificate.  This eliminates the need to click on the green
+    // "start" button.
+    _auth_button_approved = true;
+    mark_p3d_trusted();
+
+  } else {
+    // Still untrusted.
+    mark_p3d_untrusted();
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DInstance::check_p3d_signature
 //       Access: Private
@@ -984,10 +1038,7 @@ check_p3d_signature() {
   // is complete.
   return true;
 
-  nout << "check_p3d_signature\n";
   int num_signatures = _mf_reader.get_num_signatures();
-  nout << "file has " << num_signatures << " signatures\n";
-
   for (int i = 0; i < num_signatures; ++i) {
     const P3DMultifileReader::CertChain &chain = _mf_reader.get_signature(i);
 
@@ -1019,6 +1070,27 @@ void P3DInstance::
 mark_p3d_untrusted() {
   // Failed test.
   nout << "p3d untrusted\n";
+
+  if (_p3dcert_package == NULL) {
+    // We have to go download this package.
+    P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
+    P3DHost *host = inst_mgr->get_host(PANDA_PACKAGE_HOST_URL);
+    _p3dcert_package = host->get_package("p3dcert", "");
+    if (_p3dcert_package != NULL) {
+      _p3dcert_package->add_instance(this);
+    }
+    
+    // When the package finishes downloading, we will come back here.
+    return;
+  }
+
+  if (!_p3dcert_package->get_ready()) {
+    // Wait for it to finish downloading.
+    return;
+  }
+
+  // OK, we've got the authorization program; we can put up the red
+  // button now.
   set_background_image(IT_unauth);
   set_button_image(IT_auth_ready);
   make_splash_window();
@@ -1332,6 +1404,10 @@ handle_notify_request(const string &message) {
     // started Python yet).  We use this as a sneaky way to forward
     // the event from the sub-thread to the main thread.
     splash_button_clicked_main_thread();
+
+  } else if (message == "authfinished") {
+    // Similarly for the "auth finished" message.
+    auth_finished_main_thread();
   }
 }
 
@@ -1506,7 +1582,9 @@ make_splash_window() {
     if (_image_package == NULL) {
       P3DHost *host = inst_mgr->get_host(PANDA_PACKAGE_HOST_URL);
       _image_package = host->get_package("images", "");
-      _image_package->add_instance(this);
+      if (_image_package != NULL) {
+        _image_package->add_instance(this);
+      }
     }
   }
 
@@ -1607,9 +1685,18 @@ set_button_image(ImageType image_type) {
 ////////////////////////////////////////////////////////////////////
 void P3DInstance::
 report_package_info_ready(P3DPackage *package) {
-  if (package == _image_package) {
-    // A special case: the image package gets immediately downloaded,
-    // without waiting for anything else.
+  if (package == _image_package || package == _p3dcert_package) {
+    // A special case: the image package and the p3dcert package get
+    // immediately downloaded, without waiting for anything else.
+    if (package == _p3dcert_package) {
+      // If we're downloading p3dcert, though, put up a progress bar.
+      make_splash_window();
+      if (_splash_window != NULL) {
+        _splash_window->set_install_progress(0.0);
+        _splash_window->set_install_label("Getting Authorization Dialog");
+      }
+    }
+
     package->activate_download();
     return;
   }
@@ -1785,6 +1872,18 @@ report_instance_progress(double progress) {
 ////////////////////////////////////////////////////////////////////
 void P3DInstance::
 report_package_progress(P3DPackage *package, double progress) {
+  if (package == _image_package) {
+    // Ignore this.
+    return;
+  }
+  if (package == _p3dcert_package) {
+    // This gets its own progress bar.
+    if (_splash_window != NULL) {
+      _splash_window->set_install_progress(progress);
+    }
+    return;
+  }
+
   if (_download_package_index >= (int)_downloading_packages.size() ||
       package != _downloading_packages[_download_package_index]) {
     // Quietly ignore a download progress report from an unexpected
@@ -1822,6 +1921,7 @@ report_package_done(P3DPackage *package, bool success) {
       nout << "No <config> entry in image package\n";
       return;
     }
+    cerr << "downloaded image_package\n";
     for (int i = 0; i < (int)IT_none; ++i) {
       if (_image_files[i]._use_standard_image) {
         // This image indexes into the package.  Go get the standard
@@ -1838,6 +1938,7 @@ report_package_done(P3DPackage *package, bool success) {
           // still exists, put it up.
           if (_splash_window != NULL &&
               _image_files[i]._image_placement != P3DSplashWindow::IP_none) {
+            cerr << "putting up image " << i << "\n";
             P3DSplashWindow::ImagePlacement image_placement = _image_files[i]._image_placement;
             _splash_window->set_image_filename(image_filename, image_placement);
           }
@@ -1847,6 +1948,22 @@ report_package_done(P3DPackage *package, bool success) {
     return;
   }
 
+  if (package == _p3dcert_package) {
+    // Another special case: successfully downloading p3dcert means we
+    // can enable the auth button.
+
+    // Take down the download progress.
+    if (_splash_window != NULL) {
+      _splash_window->set_install_progress(0.0);
+      _splash_window->set_install_label("");
+    }
+
+    if (success) {
+      mark_p3d_untrusted();
+    }
+    return;
+  }
+
   if (success) {
     report_package_progress(package, 1.0);
     start_next_download();

+ 8 - 0
direct/src/plugin/p3dInstance.h

@@ -106,6 +106,9 @@ public:
   void auth_button_clicked();
   void play_button_clicked();
 
+  void auth_finished_sub_thread();
+  void auth_finished_main_thread();
+
 private:
   class ImageDownload : public P3DFileDownload {
   public:
@@ -209,6 +212,9 @@ private:
   P3DWindowParams _wparams;
 
   bool _p3d_trusted;
+  
+  // For downloading the p3dcert authorization program.
+  P3DPackage *_p3dcert_package;
 
   int _instance_id;
   string _session_key;
@@ -219,6 +225,7 @@ private:
   bool _auth_button_approved;
 
   P3DSession *_session;
+  P3DAuthSession *_auth_session;
 
 #ifdef __APPLE__
   // On OSX, we have to get a copy of the framebuffer data back from
@@ -275,6 +282,7 @@ private:
   BakedRequests _baked_requests;
 
   friend class P3DSession;
+  friend class P3DAuthSession;
   friend class ImageDownload;
   friend class P3DWindowParams;
   friend class P3DPackage;

+ 62 - 19
direct/src/plugin/p3dInstanceManager.cxx

@@ -15,6 +15,7 @@
 #include "p3dInstanceManager.h"
 #include "p3dInstance.h"
 #include "p3dSession.h"
+#include "p3dAuthSession.h"
 #include "p3dHost.h"
 #include "p3d_plugin_config.h"
 #include "p3dWinSplashWindow.h"
@@ -67,6 +68,8 @@ P3DInstanceManager() {
   _true_object = new P3DBoolObject(true);
   _false_object = new P3DBoolObject(false);
 
+  _auth_session = NULL;
+
 #ifdef _WIN32
   // Ensure the appropriate Windows common controls are available to
   // this application.
@@ -110,6 +113,11 @@ P3DInstanceManager::
   assert(_instances.empty());
   assert(_sessions.empty());
 
+  if (_auth_session != NULL) {
+    unref_delete(_auth_session);
+    _auth_session = NULL;
+  }
+
   Hosts::iterator hi;
   for (hi = _hosts.begin(); hi != _hosts.end(); ++hi) {
     delete (*hi).second;
@@ -381,6 +389,29 @@ finish_instance(P3DInstance *inst) {
   unref_delete(inst);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DInstanceManager::authorize_instance
+//       Access: Public
+//  Description: Creates a new P3DAuthSession object, to pop up a
+//               window for the user to authorize the certificate on
+//               this instance.  Automatically terminates any
+//               previously-created P3DAuthSession.
+////////////////////////////////////////////////////////////////////
+P3DAuthSession *P3DInstanceManager::
+authorize_instance(P3DInstance *inst) {
+  if (_auth_session != NULL) {
+    // We only want one auth_session window open at a time, to
+    // minimize user confusion, so close any previous window.
+    _auth_session->shutdown(true);
+    unref_delete(_auth_session);
+    _auth_session = NULL;
+  }
+
+  _auth_session = new P3DAuthSession(inst);
+  _auth_session->ref();
+  return _auth_session;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DInstanceManager::validate_instance
 //       Access: Public
@@ -678,25 +709,7 @@ find_cert(X509 *cert) {
   // OpenSSL's get_by_subject() approach, except we hash the whole
   // cert, not just the subject.  (Since we also store self-signed
   // certs in this list, we can't trust the subject name alone.)
-
-  static const size_t hash_size = 16;
-  unsigned char md[hash_size];
-
-  MD5_CTX ctx;
-  MD5_Init(&ctx);
-  MD5_Update(&ctx, der.data(), der.size());
-  MD5_Final(md, &ctx);
-
-  string basename;
-  static const size_t keep_hash = 6;
-  for (size_t i = 0; i < keep_hash; ++i) {
-    int high = (md[i] >> 4) & 0xf;
-    int low = md[i] & 0xf;
-    basename += P3DInstanceManager::encode_hexdigit(high);
-    basename += P3DInstanceManager::encode_hexdigit(low);
-  }
-
-  string this_cert_dir = _certs_dir + "/" + basename;
+  string this_cert_dir = get_cert_dir(cert);
   nout << "looking in " << this_cert_dir << "\n";
 
   vector<string> contents;
@@ -730,6 +743,36 @@ find_cert(X509 *cert) {
   return false;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DInstanceManager::get_cert_dir
+//       Access: Public
+//  Description: Returns the directory searched for this particular
+//               certificate.
+////////////////////////////////////////////////////////////////////
+string P3DInstanceManager::
+get_cert_dir(X509 *cert) {
+  string der = cert_to_der(cert);
+
+  static const size_t hash_size = 16;
+  unsigned char md[hash_size];
+
+  MD5_CTX ctx;
+  MD5_Init(&ctx);
+  MD5_Update(&ctx, der.data(), der.size());
+  MD5_Final(md, &ctx);
+
+  string basename;
+  static const size_t keep_hash = 6;
+  for (size_t i = 0; i < keep_hash; ++i) {
+    int high = (md[i] >> 4) & 0xf;
+    int low = md[i] & 0xf;
+    basename += P3DInstanceManager::encode_hexdigit(high);
+    basename += P3DInstanceManager::encode_hexdigit(low);
+  }
+
+  return _certs_dir + "/" + basename;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DInstanceManager::cert_to_der
 //       Access: Public, Static

+ 4 - 0
direct/src/plugin/p3dInstanceManager.h

@@ -33,6 +33,7 @@
 
 class P3DInstance;
 class P3DSession;
+class P3DAuthSession;
 class P3DHost;
 class FileSpec;
 class TiXmlElement;
@@ -75,6 +76,7 @@ public:
                         const string &p3d_filename);
   bool start_instance(P3DInstance *inst);
   void finish_instance(P3DInstance *inst);
+  P3DAuthSession *authorize_instance(P3DInstance *inst);
 
   P3DInstance *validate_instance(P3D_instance *instance);
 
@@ -98,6 +100,7 @@ public:
   void release_temp_filename(const string &filename);
 
   bool find_cert(X509 *cert);
+  string get_cert_dir(X509 *cert);
   static string cert_to_der(X509 *cert);
 
   static P3DInstanceManager *get_global_ptr();
@@ -134,6 +137,7 @@ private:
 
   typedef set<P3DInstance *> Instances;
   Instances _instances;
+  P3DAuthSession *_auth_session;
 
   typedef map<string, P3DSession *> Sessions;
   Sessions _sessions;

+ 0 - 8
direct/src/plugin/p3dSession.cxx

@@ -816,7 +816,6 @@ start_p3dpython(P3DInstance *inst) {
         }
       }
     }
-
   }
 
   // Define some new environment variables.
@@ -964,13 +963,6 @@ start_p3dpython(P3DInstance *inst) {
   _pipe_write.open_write(to_fd[1]);
 #endif // _WIN32
 
-  // Create the error stream for log output.  This means opening the
-  // logfile, if we have one, or keeping the standard error if we
-  // don't.
-#ifdef _WIN32
-#else  // _WIN32
-#endif  // _WIN32
-
   // Get the filename of the Panda3D multifile.  We need to pass this
   // to p3dpython.
   _mf_filename = inst->_panda3d->get_archive_file_pathname();

+ 1 - 0
direct/src/plugin/p3d_plugin_composite1.cxx

@@ -1,4 +1,5 @@
 #include "p3d_plugin.cxx"
+#include "p3dAuthSession.cxx"
 #include "p3dBoolObject.cxx"
 #include "p3dConcreteSequence.cxx"
 #include "p3dConcreteStruct.cxx"