pull up r19110 from trunk
authorTom Yu <tlyu@mit.edu>
Fri, 30 Mar 2007 00:35:18 +0000 (00:35 +0000)
committerTom Yu <tlyu@mit.edu>
Fri, 30 Mar 2007 00:35:18 +0000 (00:35 +0000)
 r19110@cathode-dark-space:  jaltman | 2007-01-23 19:09:13 -0500
 ticket: new
 subject: NIM Bug Fixes
 component: windows

  Document User Interface Callbacks

  Fix a race condition when performing renewal actions
  triggered by command line parameters.

  When importing credentials, kickoff a renewal after
  the credentials after the API: ccache is created.

  Another fix for identity expiration states.  This one
  fixes the behavior of the system tray icon.

ticket: 5414
version_fixed: 1.6.1

git-svn-id: svn://anonsvn.mit.edu/krb5/branches/krb5-1-6@19323 dc483132-0cff-0310-8789-dd5450dbe970

src/windows/identity/ui/appglobal.h
src/windows/identity/ui/credfuncs.c
src/windows/identity/ui/credfuncs.h
src/windows/identity/ui/credwnd.c
src/windows/identity/uilib/khnewcred.h
src/windows/identity/uilib/khuidefs.h

index 952996107e4aa012394abd5250bc304cb886f180..8660de2b47751b8fbcbe220f8791645641c803b0 100644 (file)
@@ -47,6 +47,7 @@ typedef struct tag_khm_startup_options_v1 {
     BOOL init;\r
     BOOL import;\r
     BOOL renew;\r
+    LONG pending_renewals;\r
     BOOL destroy;\r
 \r
     BOOL autoinit;\r
index dcb70480ed69b92586c49c49a46555b82ff3fde3..470af4f266c09ad9fa7b9f61339890efcbaa89a3 100644 (file)
@@ -367,6 +367,7 @@ kmsg_cred_completion(kmq_message *m)
         /* all is done. */\r
         {\r
             khui_new_creds * nc;\r
+            khm_boolean continue_cmdline = FALSE;\r
 \r
             nc = (khui_new_creds *) m->vparam;\r
 \r
@@ -379,13 +380,28 @@ kmsg_cred_completion(kmq_message *m)
                 */\r
 \r
                 khm_cred_end_dialog(nc);\r
+            } else if (nc->subtype == KMSG_CRED_RENEW_CREDS) {\r
+\r
+                /* if this is a renewal that was triggered while we\r
+                   were processing the commandline, then we need to\r
+                   update the pending renewal count. */\r
+\r
+                if (khm_startup.processing) {\r
+                    LONG renewals;\r
+                    renewals = InterlockedDecrement(&khm_startup.pending_renewals);\r
+\r
+                    if (renewals == 0) {\r
+                        continue_cmdline = TRUE;\r
+                    }\r
+                }\r
             }\r
 \r
             khui_cw_destroy_cred_blob(nc);\r
 \r
             kmq_post_message(KMSG_CRED, KMSG_CRED_REFRESH, 0, 0);\r
 \r
-            kmq_post_message(KMSG_ACT, KMSG_ACT_CONTINUE_CMDLINE, 0, 0);\r
+            if (continue_cmdline)\r
+                kmq_post_message(KMSG_ACT, KMSG_ACT_CONTINUE_CMDLINE, 0, 0);\r
         }\r
         break;\r
 \r
@@ -416,7 +432,35 @@ kmsg_cred_completion(kmq_message *m)
         break;\r
 \r
     case KMSG_CRED_IMPORT:\r
-        kmq_post_message(KMSG_ACT, KMSG_ACT_CONTINUE_CMDLINE, 0, 0);\r
+        {\r
+            khm_boolean continue_cmdline = FALSE;\r
+            LONG pending_renewals;\r
+\r
+            /* once an import operation ends, we have to trigger a\r
+               renewal so that other plug-ins that didn't participate\r
+               in the import operation can have a chance at getting\r
+               the necessary credentials.\r
+\r
+               If we are in the middle of processing the commandline,\r
+               we have to be a little bit careful.  We can't issue a\r
+               commandline conituation message right now because the\r
+               import action is still ongoing (since the renewals are\r
+               part of the action).  Once the renewals have completed,\r
+               the completion handler will automatically issue a\r
+               commandline continuation message.  However, if there\r
+               were no identities to renew, then we have to issue the\r
+               message ourselves.\r
+            */\r
+\r
+            InterlockedIncrement(&khm_startup.pending_renewals);\r
+\r
+            khm_cred_renew_all_identities();\r
+\r
+            pending_renewals = InterlockedDecrement(&khm_startup.pending_renewals);\r
+\r
+            if (pending_renewals == 0 && khm_startup.processing)\r
+                kmq_post_message(KMSG_ACT, KMSG_ACT_CONTINUE_CMDLINE, 0, 0);\r
+        }\r
         break;\r
 \r
     case KMSG_CRED_REFRESH:\r
@@ -540,6 +584,71 @@ void khm_cred_destroy_identity(khm_handle identity)
     _end_task();\r
 }\r
 \r
+void khm_cred_renew_all_identities(void)\r
+{\r
+    khm_size count;\r
+    khm_size cb = 0;\r
+    khm_size n_idents = 0;\r
+    khm_int32 rv;\r
+    wchar_t * ident_names = NULL;\r
+    wchar_t * this_ident;\r
+\r
+    kcdb_credset_get_size(NULL, &count);\r
+\r
+    /* if there are no credentials, we just skip over the renew\r
+       action. */\r
+\r
+    if (count == 0)\r
+        return;\r
+\r
+    ident_names = NULL;\r
+\r
+    while (TRUE) {\r
+        if (ident_names) {\r
+            PFREE(ident_names);\r
+            ident_names = NULL;\r
+        }\r
+\r
+        cb = 0;\r
+        rv = kcdb_identity_enum(KCDB_IDENT_FLAG_EMPTY, 0,\r
+                                NULL,\r
+                                &cb, &n_idents);\r
+\r
+        if (n_idents == 0 || rv != KHM_ERROR_TOO_LONG ||\r
+            cb == 0)\r
+            break;\r
+\r
+        ident_names = PMALLOC(cb);\r
+        ident_names[0] = L'\0';\r
+\r
+        rv = kcdb_identity_enum(KCDB_IDENT_FLAG_EMPTY, 0,\r
+                                ident_names,\r
+                                &cb, &n_idents);\r
+\r
+        if (KHM_SUCCEEDED(rv))\r
+            break;\r
+    }\r
+\r
+    if (ident_names) {\r
+        for (this_ident = ident_names;\r
+             this_ident && *this_ident;\r
+             this_ident = multi_string_next(this_ident)) {\r
+            khm_handle ident;\r
+\r
+            if (KHM_FAILED(kcdb_identity_create(this_ident, 0,\r
+                                                &ident)))\r
+                continue;\r
+\r
+            khm_cred_renew_identity(ident);\r
+\r
+            kcdb_identity_release(ident);\r
+        }\r
+\r
+        PFREE(ident_names);\r
+        ident_names = NULL;\r
+    }\r
+}\r
+\r
 void khm_cred_renew_identity(khm_handle identity)\r
 {\r
     khui_new_creds * c;\r
@@ -558,6 +667,12 @@ void khm_cred_renew_identity(khm_handle identity)
     _report_sr0(KHERR_NONE, IDS_CTX_RENEW_CREDS);\r
     _describe();\r
 \r
+    /* if we are calling this while processing startup actions, we\r
+       need to keep track of how many we have issued. */\r
+    if (khm_startup.processing) {\r
+        InterlockedIncrement(&khm_startup.pending_renewals);\r
+    }\r
+\r
     kmq_post_message(KMSG_CRED, KMSG_CRED_RENEW_CREDS, 0, (void *) c);\r
 \r
     _end_task();\r
@@ -581,6 +696,12 @@ void khm_cred_renew_cred(khm_handle cred)
     _report_sr0(KHERR_NONE, IDS_CTX_RENEW_CREDS);\r
     _describe();\r
 \r
+    /* if we are calling this while processing startup actions, we\r
+       need to keep track of how many we have issued. */\r
+    if (khm_startup.processing) {\r
+        InterlockedIncrement(&khm_startup.pending_renewals);\r
+    }\r
+\r
     kmq_post_message(KMSG_CRED, KMSG_CRED_RENEW_CREDS, 0, (void *) c);\r
 \r
     _end_task();\r
@@ -599,6 +720,12 @@ void khm_cred_renew_creds(void)
     _report_sr0(KHERR_NONE, IDS_CTX_RENEW_CREDS);\r
     _describe();\r
 \r
+    /* if we are calling this while processing startup actions, we\r
+       need to keep track of how many we have issued. */\r
+    if (khm_startup.processing) {\r
+        InterlockedIncrement(&khm_startup.pending_renewals);\r
+    }\r
+\r
     kmq_post_message(KMSG_CRED, KMSG_CRED_RENEW_CREDS, 0, (void *) c);\r
 \r
     _end_task();\r
@@ -947,73 +1074,37 @@ khm_cred_process_startup_actions(void) {
         if (khm_startup.import) {\r
             khm_cred_import();\r
             khm_startup.import = FALSE;\r
+\r
+            /* we also set the renew command to false here because we\r
+               trigger a renewal for all the identities at the end of\r
+               the import operation anyway. */\r
+            khm_startup.renew = FALSE;\r
             break;\r
         }\r
 \r
         if (khm_startup.renew) {\r
-            khm_size count;\r
-            wchar_t * ident_names = NULL;\r
-            wchar_t * this_ident;\r
-\r
-            kcdb_credset_get_size(NULL, &count);\r
+            LONG pending_renewals;\r
 \r
             /* if there are no credentials, we just skip over the\r
                renew action. */\r
 \r
             khm_startup.renew = FALSE;\r
 \r
-            if (count != 0) {\r
-                khm_size cb = 0;\r
-                khm_size n_idents = 0;\r
-                khm_int32 rv;\r
-\r
-                ident_names = NULL;\r
-\r
-                while (TRUE) {\r
-                    if (ident_names) {\r
-                        PFREE(ident_names);\r
-                        ident_names = NULL;\r
-                    }\r
-\r
-                    cb = 0;\r
-                    rv = kcdb_identity_enum(KCDB_IDENT_FLAG_EMPTY, 0,\r
-                                            NULL,\r
-                                            &cb, &n_idents);\r
-\r
-                    if (n_idents == 0 || rv != KHM_ERROR_TOO_LONG ||\r
-                        cb == 0)\r
-                        break;\r
-\r
-                    ident_names = PMALLOC(cb);\r
-\r
-                    rv = kcdb_identity_enum(KCDB_IDENT_FLAG_EMPTY, 0,\r
-                                            ident_names,\r
-                                            &cb, &n_idents);\r
+            InterlockedIncrement(&khm_startup.pending_renewals);\r
 \r
-                    if (KHM_SUCCEEDED(rv))\r
-                        break;\r
-                }\r
-\r
-                if (ident_names) {\r
-                    for (this_ident = ident_names;\r
-                         this_ident && *this_ident;\r
-                         this_ident = multi_string_next(this_ident)) {\r
-                        khm_handle ident;\r
-\r
-                        if (KHM_FAILED(kcdb_identity_create(this_ident, 0,\r
-                                                            &ident)))\r
-                            continue;\r
-\r
-                        khm_cred_renew_identity(ident);\r
+            khm_cred_renew_all_identities();\r
 \r
-                        kcdb_identity_release(ident);\r
-                    }\r
+            pending_renewals = InterlockedDecrement(&khm_startup.pending_renewals);\r
 \r
-                    PFREE(ident_names);\r
-                    ident_names = NULL;\r
-                }\r
+            if (pending_renewals != 0)\r
                 break;\r
-            }\r
+\r
+            /* if there were no pending renewals, then we just fall\r
+               through. This means that either there were no\r
+               identities to renew, or all the renewals completed.  If\r
+               all the renewals completed, then the commandline\r
+               contiuation message wasn't triggered.  Either way, we\r
+               must fall through if the count is zero. */\r
         }\r
 \r
         if (khm_startup.destroy) {\r
index 379573ff523a38b7425f66a57d1d9ccf16a613ab..b3c88faa4b4716b936ce18bd9666faa2956008b1 100644 (file)
@@ -38,6 +38,9 @@ khm_cred_destroy_creds(khm_boolean sync,
 void\r
 khm_cred_destroy_identity(khm_handle identity);\r
 \r
+void\r
+khm_cred_renew_all_identities(void);\r
+\r
 void \r
 khm_cred_renew_identity(khm_handle identity);\r
 \r
index d8dfcc50386904936ecb79c814c4a74225b10811..5bdbdb754d088209c2980f6735a1d2b31d825628 100644 (file)
@@ -1254,6 +1254,7 @@ cw_update_outline(khui_credwnd_tbl * tbl)
                 if (flags) {\r
                     ol->flags |= flags;\r
                     ol->flags |= KHUI_CW_O_SHOWFLAG;\r
+                   expstate |= flags;\r
                 }\r
             }\r
         }\r
@@ -1264,7 +1265,6 @@ cw_update_outline(khui_credwnd_tbl * tbl)
             visible = visible && (ol->flags & KHUI_CW_O_EXPAND);\r
 \r
         flags = cw_get_buf_exp_flags(tbl, thiscred);\r
-        expstate |= flags;\r
 \r
         if(visible) {\r
             khm_int32 c_flags;\r
@@ -1404,6 +1404,8 @@ _exit:
     if(grouping)\r
         PFREE(grouping);\r
 \r
+    /* note that the expstate is derived from whether or not \r
+     * we have expiration states set for any active identities */\r
     if (n_creds == 0)\r
         khm_notify_icon_expstate(KHM_NOTIF_EMPTY);\r
     else if (expstate & CW_EXPSTATE_EXPIRED)\r
index b2b014e4f3978dacc2d0474dc859ef284c1c280d..1785d5972cafa49363543665a74c11f99fb215e9 100644 (file)
@@ -225,9 +225,9 @@ typedef struct tag_khui_new_creds {
 \r
     khm_int32   subtype;        /*!< Subtype of the request that is\r
                                   being handled through this object.\r
-                                  One of ::KMSG_CRED_INITIAL_CREDS,\r
-                                  ::KMSG_CRED_NEW_CREDS or\r
-                                  ::KMSG_CRED_RENEW_CREDS */\r
+                                  One of ::KMSG_CRED_NEW_CREDS,\r
+                                  ::KMSG_CRED_RENEW_CREDS or\r
+                                  ::KMSG_CRED_PASSWORD */\r
 \r
     CRITICAL_SECTION cs;        /*!< Internal use */\r
 \r
index 7df605cc74a07d33511253f049d404323f999794..845f781d29b0eac494186ad10c2a1929e307bb40 100644 (file)
@@ -88,9 +88,39 @@ khm_get_lib_version(khm_version * libver, khm_ui_4 * apiver);
 KHMEXP khm_ui_4 KHMAPI\r
 khm_get_commctl_version(khm_version * pdvi);\r
 \r
+/*! \brief UI callback function\r
+\r
+    Used with khui_request_UI_callback().\r
+\r
+    \see khui_request_UI_callback()\r
+ */\r
 typedef khm_int32\r
 (KHMAPI *khm_ui_callback)(HWND hwnd_main_wnd, void * rock);\r
 \r
+/*! \brief Request a UI callback\r
+\r
+    In general, plug-ins in Network Identity Manager run in their own\r
+    thread and will not be able to interact with the user directly by\r
+    creating windows of its own.  There are exceptions to this, such\r
+    as when the plug-in is responding to a new credentials request or\r
+    if the plug-in provides configuration panels.  However, if a\r
+    plug-in needs to provide a user interface to the user outside of\r
+    the provisions already provided by Network Identity Manager, it\r
+    needs to do so from within the user interface thread.\r
+\r
+    To do so, a plug-in would provide a callback function of the type\r
+    ::khm_ui_callback to this function.  The Network Identity Manager\r
+    will then call the callback function from within the user\r
+    interface thread.  At this point, the callback function can create\r
+    any windows it wishes to create and interact with the user\r
+    directly.\r
+\r
+    Note that when the plug-in creates any windows, it should specify\r
+    the window handle provided via the \a hwnd_main_wnd parameter as\r
+    the parent window.\r
+\r
+    \see ::khm_ui_callback\r
+ */\r
 KHMEXP khm_int32 KHMAPI\r
 khui_request_UI_callback(khm_ui_callback cb, void * rock);\r
 \r