Browse Source

wip: authwindow

David Rose 16 years ago
parent
commit
68a6ddf163

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

@@ -25,6 +25,7 @@
     p3d_lock.h p3d_plugin.h \
     p3d_plugin_config.h \
     p3d_plugin_common.h \
+    p3dAuthDialog.h p3dAuthDialog.I \
     p3dBoolObject.h \
     p3dConcreteSequence.h \
     p3dConcreteStruct.h \
@@ -50,6 +51,7 @@
     p3dStringObject.h \
     p3dTemporaryFile.h p3dTemporaryFile.I \
     p3dUndefinedObject.h \
+    p3dWinAuthDialog.h \
     p3dWinSplashWindow.h p3dWinSplashWindow.I \
     p3dX11SplashWindow.h p3dX11SplashWindow.I \
     p3dWindowParams.h p3dWindowParams.I \
@@ -57,6 +59,7 @@
 
   #define INCLUDED_SOURCES \
     p3d_plugin.cxx \
+    p3dAuthDialog.cxx \
     p3dBoolObject.cxx \
     p3dConcreteSequence.cxx \
     p3dConcreteStruct.cxx \
@@ -82,6 +85,7 @@
     p3dStringObject.cxx \
     p3dTemporaryFile.cxx \
     p3dUndefinedObject.cxx \
+    p3dWinAuthDialog.cxx \
     p3dWinSplashWindow.cxx \
     p3dX11SplashWindow.cxx \
     p3dWindowParams.cxx

+ 14 - 0
direct/src/plugin/p3dAuthDialog.I

@@ -0,0 +1,14 @@
+// Filename: p3dAuthDialog.I
+// Created by:  drose (16Sep09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+

+ 212 - 0
direct/src/plugin/p3dAuthDialog.cxx

@@ -0,0 +1,212 @@
+// Filename: p3dAuthDialog.cxx
+// Created by:  drose (16Sep09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "p3dAuthDialog.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DAuthDialog::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+P3DAuthDialog::
+P3DAuthDialog() {
+  _cert = NULL;
+  _verify_status = VS_no_cert;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DAuthDialog::Destructor
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+P3DAuthDialog::
+~P3DAuthDialog() {
+  close();
+  clear_cert();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DAuthDialog::read_cert
+//       Access: Public
+//  Description: Reads the indicated certificate chain and stores the
+//               first certificate in _x509 and its common name in
+//               _common_name; also checks whether the certificate is
+//               valid by the chain and initializes _verify_status
+//               accordingly.
+////////////////////////////////////////////////////////////////////
+void P3DAuthDialog::
+read_cert(const P3DMultifileReader::CertChain &cert_chain) {
+  clear_cert();
+  if (cert_chain.empty()) {
+    _verify_status = VS_no_cert;
+    return;
+  }
+
+  _cert = X509_dup(cert_chain[0]._cert);
+
+  // A complex OpenSSL interface to extract out the common name in
+  // utf-8.
+  X509_NAME *xname = X509_get_subject_name(cert_chain[0]._cert);
+  if (xname != NULL) {
+    int pos = X509_NAME_get_index_by_NID(xname, NID_commonName, -1);
+    if (pos != -1) {
+      // We just get the first common name.  I guess it's possible to
+      // have more than one; not sure what that means in this context.
+      X509_NAME_ENTRY *xentry = X509_NAME_get_entry(xname, pos);
+      if (xentry != NULL) {
+        ASN1_STRING *data = X509_NAME_ENTRY_get_data(xentry);
+        if (data != NULL) {
+          // We use "print" to dump the output to a memory BIO.  Is
+          // there an easier way to decode the ASN1_STRING?  Curse
+          // these incomplete docs.
+          BIO *mbio = BIO_new(BIO_s_mem());
+          ASN1_STRING_print_ex(mbio, data, ASN1_STRFLGS_RFC2253 & ~ASN1_STRFLGS_ESC_MSB);
+
+          char *pp;
+          long pp_size = BIO_get_mem_data(mbio, &pp);
+          string name(pp, pp_size);
+          BIO_free(mbio);
+          _common_name = name;
+        }
+      }
+    }
+  }
+
+  // Now validate the signature.
+
+  // Create a STACK of everything following the first cert.
+  STACK *stack = NULL;
+  if (cert_chain.size() > 1) {
+    stack = sk_new(NULL);
+    for (size_t n = 1; n < cert_chain.size(); ++n) {
+      sk_push(stack, (char *)cert_chain[n]._cert);
+    }
+  }
+
+  // Create a new X509_STORE.
+  X509_STORE *store = X509_STORE_new();
+  X509_STORE_set_default_paths(store);
+
+  // Create the X509_STORE_CTX for verifying the cert and chain.
+  X509_STORE_CTX *ctx = X509_STORE_CTX_new();
+  X509_STORE_CTX_init(ctx, store, _cert, stack);
+  X509_STORE_CTX_set_cert(ctx, _cert);
+
+  if (X509_verify_cert(ctx)) {
+    _verify_status = VS_verified;
+  } else {
+    int verify_result = X509_STORE_CTX_get_error(ctx);
+    switch (verify_result) {
+    case X509_V_ERR_CERT_NOT_YET_VALID:
+    case X509_V_ERR_CERT_HAS_EXPIRED:
+    case X509_V_ERR_CRL_NOT_YET_VALID:
+    case X509_V_ERR_CRL_HAS_EXPIRED:
+      _verify_status = VS_expired;
+      break;
+      
+    case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
+    case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
+      _verify_status = VS_self_signed;
+      break;
+
+    default:
+      _verify_status = VS_other;
+    }
+  }
+
+  sk_free(stack);
+  X509_STORE_CTX_cleanup(ctx);
+  X509_STORE_CTX_free(ctx);
+
+  X509_STORE_free(store);
+
+  nout << "Got certificate from " << _common_name
+       << ", verify_status = " << _verify_status << "\n";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DAuthDialog::clear_cert
+//       Access: Public
+//  Description: Clears the data allocated by read_cert().
+////////////////////////////////////////////////////////////////////
+void P3DAuthDialog::
+clear_cert() {
+  if (_cert != NULL){ 
+    X509_free(_cert);
+    _cert = NULL;
+  }
+  
+  _common_name.clear();
+  _verify_status = VS_no_cert;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DAuthDialog::open
+//       Access: Public, Virtual
+//  Description: Displays the dialog and waits for user to click a
+//               button.
+////////////////////////////////////////////////////////////////////
+void P3DAuthDialog::
+open() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DAuthDialog::close
+//       Access: Public, Virtual
+//  Description: Closes the dialog prematurely.
+////////////////////////////////////////////////////////////////////
+void P3DAuthDialog::
+close() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DAuthDialog::get_text
+//       Access: Protected
+//  Description: Fills in the text appropriate to display in the
+//               dialog box, based on the certificate read so far.
+////////////////////////////////////////////////////////////////////
+void P3DAuthDialog::
+get_text(string &header, string &text) {
+  switch (_verify_status) {
+  case VS_verified:
+    text = "This Panda3D application has been signed by ";
+    text += _common_name;
+    text += ".\n\nIf you trust ";
+    text += _common_name;
+    text += ", then click the Run button below\n";
+    text += "to run this application on your computer.  This will also\n";
+    text += "automatically approve this and any other applications signed by\n";
+    text += _common_name;
+    text += " in the future.\n\n";
+    text += "If you are unsure about this application,\n";
+    text += "you should click Cancel instead.";
+    return;
+
+  case VS_self_signed:
+    header = "Unverified signature!\n";
+    text = "This Panda3D application has been signed by what's known as a\n";
+    text += "self-signed certificate.  This means the name on the certificate can't\n";
+    text += "be verified, and you have no way of knowing for sure who wrote it.\n\n";
+    text += "We recommend you click Cancel to avoid running this application.";
+    return;
+
+  case VS_no_cert:
+    header = "No signature!\n";
+    text = "This Panda3D application has not been signed.";
+    return;
+
+  default:
+    text = "Undefined text.";
+  }
+}

+ 63 - 0
direct/src/plugin/p3dAuthDialog.h

@@ -0,0 +1,63 @@
+// Filename: p3dAuthDialog.h
+// Created by:  drose (16Sep09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef P3DAUTHDIALOG_H
+#define P3DAUTHDIALOG_H
+
+#include "p3d_plugin_common.h"
+#include "p3dMultifileReader.h"
+#include "p3dInstanceManager.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : P3DAuthDialog
+// Description : This dialog is presented to the user when he/she
+//               clicks on the red authorization button on the splash
+//               window.  It tells the user the status of the
+//               application's signature, and invites the user to
+//               approve the signature or cancel.
+//
+//               This is the base implementation; it contains no
+//               specific code to open a window.
+////////////////////////////////////////////////////////////////////
+class P3DAuthDialog {
+public:
+  P3DAuthDialog();
+  virtual ~P3DAuthDialog();
+
+  void read_cert(const P3DMultifileReader::CertChain &cert_chain);
+  void clear_cert();
+
+  virtual void open();
+  virtual void close();
+
+protected:
+  void get_text(string &header, string &text);
+
+protected:
+  X509 *_cert;
+  string _common_name;
+
+  enum VerifyStatus {
+    VS_verified,
+    VS_self_signed,
+    VS_expired,
+    VS_no_cert,
+    VS_other,
+  };
+  VerifyStatus _verify_status;
+};
+
+#include "p3dAuthDialog.I"
+
+#endif

+ 15 - 11
direct/src/plugin/p3dInstance.cxx

@@ -931,6 +931,20 @@ auth_button_clicked() {
   // Here's where we need to invoke the authorization program.
   cerr << "auth clicked\n";
 
+  assert(_splash_window != NULL);
+  int num_signatures = _mf_reader.get_num_signatures();
+  if (num_signatures > 0) {
+    // Ask the user to approve the first certificate.
+    _splash_window->show_auth_dialog(_mf_reader.get_signature(0));
+
+  } else {
+    // Unsigned application!  We'll give the user a dialog to tell him
+    // the bad news.  Presumbly the "user" here is the developer
+    // attempting to host his own application in a web page.
+    _splash_window->show_auth_dialog(P3DMultifileReader::CertChain());
+  }
+
+  /*
   // After the authorization program has returned, check the signature
   // again.
   if (check_p3d_signature()) {
@@ -942,6 +956,7 @@ auth_button_clicked() {
   } else {
     mark_p3d_untrusted();
   }
+  */
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -979,17 +994,6 @@ check_p3d_signature() {
     return true;
   }
 
-  /*
-  if (_browser_script_object != NULL) {
-    P3D_object *result = P3D_OBJECT_EVAL(_browser_script_object, "if (confirm('test')) { window.open('', 'test', ''); }");
-    cerr << "result = " << result << "\n";
-    if (result != NULL) {
-      cerr << "formatted: " << *result << "\n";
-      P3D_OBJECT_DECREF(result);
-    }
-  }
-  */
-
   // Temporary hack: disabling further security checks until this code
   // is complete.
   return true;

+ 11 - 0
direct/src/plugin/p3dSplashWindow.cxx

@@ -152,6 +152,17 @@ set_button_active(bool flag) {
   set_mouse_data(_mouse_x, _mouse_y, _mouse_down);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DSplashWindow::show_auth_dialog
+//       Access: Public, Virtual
+//  Description: Pops up a P3DAuthDialog of a type appropriate to the
+//               current platform, to allow the user to approve (or
+//               deny) the indicated certificate chain.
+////////////////////////////////////////////////////////////////////
+void P3DSplashWindow::
+show_auth_dialog(const P3DMultifileReader::CertChain &cert_chain) {
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DSplashWindow::read_image_data
 //       Access: Protected

+ 4 - 1
direct/src/plugin/p3dSplashWindow.h

@@ -12,13 +12,13 @@
 //
 ////////////////////////////////////////////////////////////////////
 
-
 #ifndef P3DSPLASHWINDOW_H
 #define P3DSPLASHWINDOW_H
 
 #include "p3d_plugin_common.h"
 #include "p3dFileParams.h"
 #include "p3dWindowParams.h"
+#include "p3dMultifileReader.h"
 
 class P3DInstance;
 
@@ -59,6 +59,9 @@ public:
 
   virtual void set_button_active(bool flag);
 
+  virtual void show_auth_dialog(const P3DMultifileReader::CertChain &cert_chain);
+
+
 protected:
   // This ImageData base class provides minimal functionality for
   // storing a loaded image.  Most of the real meat of this class is

+ 328 - 0
direct/src/plugin/p3dWinAuthDialog.cxx

@@ -0,0 +1,328 @@
+// Filename: p3dWinAuthDialog.cxx
+// Created by:  drose (16Sep09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "p3dWinAuthDialog.h"
+
+#ifdef _WIN32
+
+bool P3DWinAuthDialog::_registered_window_class = false;
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DWinAuthDialog::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+P3DWinAuthDialog::
+P3DWinAuthDialog() {
+  _hwnd = NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DWinAuthDialog::open
+//       Access: Public, Virtual
+//  Description: Displays the dialog and waits for user to click a
+//               button.
+////////////////////////////////////////////////////////////////////
+void P3DWinAuthDialog::
+open() {
+  close();
+  make_window();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DWinAuthDialog::close
+//       Access: Public, Virtual
+//  Description: Closes the dialog prematurely.
+////////////////////////////////////////////////////////////////////
+void P3DWinAuthDialog::
+close() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DWinAuthDialog::register_window_class
+//       Access: Public, Static
+//  Description: Registers the window class for this window, if
+//               needed.
+////////////////////////////////////////////////////////////////////
+void P3DWinAuthDialog::
+register_window_class() {
+  if (!_registered_window_class) {
+    HINSTANCE application = GetModuleHandle(NULL);
+
+    WNDCLASS wc;
+    ZeroMemory(&wc, sizeof(WNDCLASS));
+    wc.lpfnWndProc = st_window_proc;
+    wc.hInstance = application;
+    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+    wc.hbrBackground = HBRUSH(COLOR_WINDOW + 1);
+    wc.lpszClassName = "panda3d_auth_dialog";
+    
+    if (!RegisterClass(&wc)) {
+      nout << "Could not register window class panda3d_auth_dialog\n";
+    }
+    _registered_window_class = true;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DWinAuthDialog::unregister_window_class
+//       Access: Public, Static
+//  Description: Unregisters the window class for this window.  It is
+//               necessary to do this before unloading the DLL.
+////////////////////////////////////////////////////////////////////
+void P3DWinAuthDialog::
+unregister_window_class() {
+  if (_registered_window_class) {
+    HINSTANCE application = GetModuleHandle(NULL);
+
+    if (!UnregisterClass("panda3d_splash", application)) {
+      nout << "Could not unregister window class panda3d_splash\n";
+    }
+    _registered_window_class = false;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DWinAuthDialog::make_window
+//       Access: Private
+//  Description: Creates the window.
+////////////////////////////////////////////////////////////////////
+void P3DWinAuthDialog::
+make_window() {
+  register_window_class();
+  HINSTANCE application = GetModuleHandle(NULL);
+  
+  int x = CW_USEDEFAULT;
+  int y = CW_USEDEFAULT;
+  
+  int width = 320;
+  int height = 240;
+
+  // Create a toplevel window.
+  DWORD window_style = 
+    WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS |
+    WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU;
+  
+  _hwnd = 
+    CreateWindow("panda3d_auth_dialog", "New Panda3D Application",
+                 window_style,
+                 x, y, width, height,
+                 NULL, NULL, application, 0);
+  if (!_hwnd) {
+    nout << "Could not create toplevel window!\n";
+    return;
+  }
+
+  SetWindowLongPtr(_hwnd, GWLP_USERDATA, (LONG_PTR)this);
+
+  // Stack items vertically from the top of the window.
+  static const int margin = 10;
+  int cy = margin;
+  int maxx = 0;
+
+  // Set up the window text.
+  string header, text;
+  get_text(header, text);
+
+  HFONT font = (HFONT)GetStockObject(ANSI_VAR_FONT); 
+
+  HWND header_label = NULL;
+  int header_width, header_height;
+  if (!header.empty()) {
+    header_label = make_static_text(header_width, header_height, font, header);
+    SetWindowPos(header_label, 0, margin, cy, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
+    cy += header_height;
+    maxx = max(maxx, header_width);
+    cy += margin;
+  }
+
+  int text_width, text_height;
+  HWND text_label = make_static_text(text_width, text_height, font, text);
+  SetWindowPos(text_label, 0, margin, cy, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
+  cy += text_height;
+  maxx = max(maxx, text_width);
+  cy += margin;
+
+  if (header_label != NULL && header_width < text_width) {
+    // Make the header as wide as the text to center it.
+    SetWindowPos(header_label, 0, 0, 0, text_width, header_height,
+                 SWP_NOZORDER | SWP_NOMOVE);
+  }
+
+  // Now make a button.
+  int button_width, button_height;
+  HWND cancel_button = make_button(button_width, button_height, "Cancel");
+  SetWindowPos(cancel_button, 0, margin, cy, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
+  cy += button_height;
+  maxx = max(maxx, button_width);
+
+  {
+    HDC dc = GetDC(cancel_button);
+    SelectObject(dc, font);
+    ReleaseDC(cancel_button, dc);
+  }
+
+  // Make the window an appropriate size for all its items.
+  cy += margin;
+  int cx = maxx + margin * 2;
+
+  // Compensate for the window title and border.
+  RECT win_rect = { 0, 0, cx, cy };
+  AdjustWindowRect(&win_rect, window_style, FALSE);
+
+  SetWindowPos(_hwnd, HWND_TOP, 0, 0, 
+               win_rect.right - win_rect.left, win_rect.bottom - win_rect.top, 
+               SWP_NOMOVE);
+
+  ShowWindow(_hwnd, SW_SHOWNORMAL);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DWinAuthDialog::make_button
+//       Access: Private
+//  Description: Creates a standard button object with the indicated
+//               label.
+////////////////////////////////////////////////////////////////////
+HWND P3DWinAuthDialog::
+make_button(int &width, int &height, const string &label) {
+  HINSTANCE application = GetModuleHandle(NULL);
+
+  DWORD window_style = 
+    BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
+
+  width = 64;
+  height = 24;
+
+  HWND button = CreateWindowEx(0, "BUTTON", label.c_str(), window_style,
+                               0, 0, width, height,
+                               _hwnd, (HMENU)1, application, 0);
+  return button;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DWinAuthDialog::make_static_text
+//       Access: Private
+//  Description: Creates a static text object for displaying the
+//               indicated text block with the given font.
+////////////////////////////////////////////////////////////////////
+HWND P3DWinAuthDialog::
+make_static_text(int &width, int &height, HFONT font, 
+                 const string &text) {
+  HINSTANCE application = GetModuleHandle(NULL);
+
+  DWORD window_style = 
+    SS_OWNERDRAW | WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
+
+  measure_text(width, height, font, text);
+  HWND label = CreateWindowEx(0, "STATIC", text.c_str(), window_style,
+                              0, 0, width, height,
+                              _hwnd, NULL, application, 0);
+  HDC dc = GetDC(label);
+  SelectObject(dc, font);
+  ReleaseDC(label, dc);
+  
+  return label;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DWinAuthDialog::measure_text
+//       Access: Private
+//  Description: Determines the height and width of the indicated
+//               string of text, using the indicated font.
+////////////////////////////////////////////////////////////////////
+void P3DWinAuthDialog::
+measure_text(int &width, int &height, HFONT font, const string &text) {
+  HDC dc = GetDC(_hwnd);
+  SelectObject(dc, font);
+
+  width = 0;
+  height = 0;
+  SIZE text_size;
+
+  // GetTextExtentPoint() only works for one line at a time.
+  const char *text_data = text.data();
+  size_t start = 0;
+  size_t newline = text.find('\n');
+  while (newline != string::npos) {
+    string line(text_data + start, newline - start);
+    if (line.empty()) {
+      line = " ";
+    }
+    GetTextExtentPoint32(dc, line.data(), line.size(), &text_size);
+    width = max(width, text_size.cx); 
+    height += text_size.cy;
+
+    start = newline + 1;
+    newline = text.find('\n', start);
+  }
+
+  GetTextExtentPoint32(dc, text_data + start, text.size() - start, &text_size);
+  width = max(width, text_size.cx); 
+  height += text_size.cy;
+
+  ReleaseDC(_hwnd, dc);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DWinAuthDialog::window_proc
+//       Access: Private
+//  Description: The windows event-processing handler.
+////////////////////////////////////////////////////////////////////
+LONG P3DWinAuthDialog::
+window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
+  switch (msg) {
+  case WM_COMMAND:
+    cerr << "WM_COMMAND " << wparam << " " << lparam << "\n";
+    break;
+
+  case WM_DRAWITEM:
+    // Draw a text label placed within the window.
+    {
+      DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)lparam;
+      FillRect(dis->hDC, &(dis->rcItem), WHITE_BRUSH);
+
+      static const int text_buffer_size = 512;
+      char text_buffer[text_buffer_size];
+      GetWindowText(dis->hwndItem, text_buffer, text_buffer_size);
+
+      HFONT font = (HFONT)GetStockObject(ANSI_VAR_FONT); 
+      SelectObject(dis->hDC, font);
+      SetBkColor(dis->hDC, 0x00ffffff);
+
+      DrawText(dis->hDC, text_buffer, -1, &(dis->rcItem), 
+               DT_CENTER);
+    }
+    return true;
+  };
+
+  return DefWindowProc(hwnd, msg, wparam, lparam);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DWinAuthDialog::st_window_proc
+//       Access: Private, Static
+//  Description: The windows event-processing handler, static version.
+////////////////////////////////////////////////////////////////////
+LONG P3DWinAuthDialog::
+st_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
+  LONG_PTR self = GetWindowLongPtr(hwnd, GWLP_USERDATA);
+  if (self == NULL) {
+    // We haven't assigned the pointer yet.
+    return DefWindowProc(hwnd, msg, wparam, lparam);
+  }
+
+  return ((P3DWinAuthDialog *)self)->window_proc(hwnd, msg, wparam, lparam);
+}
+
+#endif  // _WIN32

+ 57 - 0
direct/src/plugin/p3dWinAuthDialog.h

@@ -0,0 +1,57 @@
+// Filename: p3dWinAuthDialog.h
+// Created by:  drose (16Sep09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef P3DWINAUTHDIALOG_H
+#define P3DWINAUTHDIALOG_H
+
+#include "p3dAuthDialog.h"
+
+#ifdef _WIN32
+
+////////////////////////////////////////////////////////////////////
+//       Class : P3DWinAuthDialog
+// Description : A specialization on P3DAuthDialog for windows.
+////////////////////////////////////////////////////////////////////
+class P3DWinAuthDialog : public P3DAuthDialog {
+public:
+  P3DWinAuthDialog();
+
+  virtual void open();
+  virtual void close();
+
+  static void register_window_class();
+  static void unregister_window_class();
+
+private:
+  void make_window();
+
+  HWND make_button(int &width, int &height, const string &label);
+  HWND make_static_text(int &width, int &height, HFONT font, 
+                        const string &text);
+  void measure_text(int &width, int &height, HFONT font, const string &text);
+
+  LONG window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
+  static LONG WINAPI st_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
+
+private:
+  HWND _hwnd;
+
+  static bool _registered_window_class;
+};
+
+#include "p3dAuthDialog.I"
+
+#endif  // _WIN32
+
+#endif

+ 49 - 21
direct/src/plugin/p3dWinSplashWindow.cxx

@@ -16,6 +16,8 @@
 
 #ifdef _WIN32
 
+#include "p3dWinAuthDialog.h"
+
 bool P3DWinSplashWindow::_registered_window_class = false;
 
 ////////////////////////////////////////////////////////////////////
@@ -33,10 +35,13 @@ P3DWinSplashWindow(P3DInstance *inst) :
   _blue_brush = NULL;
   _thread_running = false;
   _install_progress = 0.0;
+  _needs_auth_dialog = false;
 
   _drawn_bstate = BS_hidden;
   _drawn_progress = 0.0;
 
+  _auth_dialog = NULL;
+
   INIT_LOCK(_install_lock);
 }
 
@@ -166,6 +171,33 @@ set_install_progress(double install_progress) {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DWinSplashWindow::show_auth_dialog
+//       Access: Public, Virtual
+//  Description: Pops up a P3DAuthDialog of a type appropriate to the
+//               current platform, to allow the user to approve (or
+//               deny) the indicated certificate chain.
+////////////////////////////////////////////////////////////////////
+void P3DWinSplashWindow::
+show_auth_dialog(const P3DMultifileReader::CertChain &cert_chain) {
+  // We need to direct this request into the sub-thread.
+  ACQUIRE_LOCK(_install_lock);
+  _needs_auth_dialog = true;
+  _auth_cert_chain = cert_chain;
+  RELEASE_LOCK(_install_lock);
+
+  if (_thread_id != 0) {
+    // Post a silly message to spin the message loop.
+    PostThreadMessage(_thread_id, WM_USER, 0, 0);
+
+    if (!_thread_running && _thread_continue) {
+      // The user must have closed the window.  Let's shut down the
+      // instance, too.
+      _inst->request_stop();
+    }
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DWinSplashWindow::register_window_class
 //       Access: Public, Static
@@ -290,6 +322,18 @@ thread_run() {
 
     ACQUIRE_LOCK(_install_lock);
 
+    if (_needs_auth_dialog) {
+      // A request from the main thread to pop up an auth dialog.
+      _needs_auth_dialog = false;
+
+      if (_auth_dialog != NULL) {
+        delete _auth_dialog;
+      }
+      _auth_dialog = new P3DWinAuthDialog;
+      _auth_dialog->read_cert(_auth_cert_chain);
+      _auth_dialog->open();
+    }
+
     update_image(_background_image);
     update_image(_button_ready_image);
     update_image(_button_rollover_image);
@@ -578,6 +622,11 @@ close_window() {
   _button_ready_image.dump_image();
   _button_rollover_image.dump_image();
   _button_click_image.dump_image();
+
+  if (_auth_dialog != NULL) {
+    delete _auth_dialog;
+    _auth_dialog = NULL;
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -784,27 +833,6 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
     }
     return true;
 
-    /*
-  case WM_DRAWITEM:
-    // Draw a text label placed within the window.
-    {
-      DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)lparam;
-      FillRect(dis->hDC, &(dis->rcItem), WHITE_BRUSH);
-
-      static const int text_buffer_size = 512;
-      char text_buffer[text_buffer_size];
-      GetWindowText(dis->hwndItem, text_buffer, text_buffer_size);
-
-      HFONT font = (HFONT)GetStockObject(ANSI_VAR_FONT); 
-      SelectObject(dis->hDC, font);
-      SetBkColor(dis->hDC, 0x00ffffff);
-
-      DrawText(dis->hDC, text_buffer, -1, &(dis->rcItem), 
-               DT_VCENTER | DT_CENTER | DT_SINGLELINE);
-    }
-    return true;
-    */
-
   case WM_MOUSEMOVE: 
     set_mouse_data(LOWORD(lparam), HIWORD(lparam), _mouse_down);
     break;

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

@@ -22,6 +22,8 @@
 #include "p3dSplashWindow.h"
 #include "p3d_lock.h"
 
+class P3DWinAuthDialog;
+
 #include <windows.h>
 
 ////////////////////////////////////////////////////////////////////
@@ -40,6 +42,8 @@ public:
   virtual void set_install_label(const string &install_label);
   virtual void set_install_progress(double install_progress);
 
+  virtual void show_auth_dialog(const P3DMultifileReader::CertChain &cert_chain);
+
   static void register_window_class();
   static void unregister_window_class();
 
@@ -87,6 +91,8 @@ private:
   bool _got_install;
   string _install_label;
   double _install_progress;
+  bool _needs_auth_dialog;
+  P3DMultifileReader::CertChain _auth_cert_chain;
   LOCK _install_lock;
 
   ButtonState _drawn_bstate;
@@ -100,6 +106,8 @@ private:
   HWND _hwnd;
   HBRUSH _blue_brush;
 
+  P3DWinAuthDialog *_auth_dialog;
+
   static bool _registered_window_class;
 };
 

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

@@ -1,4 +1,5 @@
 #include "p3d_plugin.cxx"
+#include "p3dAuthDialog.cxx"
 #include "p3dBoolObject.cxx"
 #include "p3dConcreteSequence.cxx"
 #include "p3dConcreteStruct.cxx"
@@ -24,6 +25,7 @@
 #include "p3dTemporaryFile.cxx"
 #include "p3dMainObject.cxx"
 #include "p3dUndefinedObject.cxx"
+#include "p3dWinAuthDialog.cxx"
 #include "p3dWinSplashWindow.cxx"
 #include "p3dX11SplashWindow.cxx"
 #include "p3dWindowParams.cxx"