windows-netidmgr-plugin-20061010
authorAsanka Herath <asanka@secure-endpoints.com>
Wed, 11 Oct 2006 05:32:16 +0000 (05:32 +0000)
committerJeffrey Altman <jaltman@secure-endpoints.com>
Wed, 11 Oct 2006 05:32:16 +0000 (05:32 +0000)
Secure Endpoints Inc. is contributing its AFS plug-in for KFW 3.1's
Network Identity Manager to OpenAFS under an MIT style license.

62 files changed:
src/NTMakefile
src/WINNT/install/NSIS/OpenAFS.nsi
src/WINNT/install/wix/feature.wxi
src/WINNT/install/wix/files.wxi
src/WINNT/install/wix/lang/en_US/strings.wxl
src/WINNT/install/wix/openafs.wxs
src/WINNT/install/wix/platform.wxi
src/WINNT/netidmgr_plugin/NTMakefile [new file with mode: 0644]
src/WINNT/netidmgr_plugin/afsconfig.c [new file with mode: 0644]
src/WINNT/netidmgr_plugin/afsconfigdlg.c [new file with mode: 0644]
src/WINNT/netidmgr_plugin/afscred.h [new file with mode: 0644]
src/WINNT/netidmgr_plugin/afsext.c [new file with mode: 0644]
src/WINNT/netidmgr_plugin/afsfuncs.c [new file with mode: 0644]
src/WINNT/netidmgr_plugin/afsfuncs.h [new file with mode: 0644]
src/WINNT/netidmgr_plugin/afshelp.c [new file with mode: 0644]
src/WINNT/netidmgr_plugin/afsnewcreds.c [new file with mode: 0644]
src/WINNT/netidmgr_plugin/afsnewcreds.h [new file with mode: 0644]
src/WINNT/netidmgr_plugin/afsp_version.h [new file with mode: 0644]
src/WINNT/netidmgr_plugin/afsp_version.h.in [new file with mode: 0644]
src/WINNT/netidmgr_plugin/afspext.h [new file with mode: 0644]
src/WINNT/netidmgr_plugin/afsplugin.c [new file with mode: 0644]
src/WINNT/netidmgr_plugin/afsplugin_custom.c [new file with mode: 0644]
src/WINNT/netidmgr_plugin/dynimport.c [new file with mode: 0644]
src/WINNT/netidmgr_plugin/dynimport.h [new file with mode: 0644]
src/WINNT/netidmgr_plugin/help/Index.hhk [new file with mode: 0644]
src/WINNT/netidmgr_plugin/help/NTMakefile [new file with mode: 0644]
src/WINNT/netidmgr_plugin/help/afsplhlp.h [new file with mode: 0644]
src/WINNT/netidmgr_plugin/help/afsplhlp.hhp [new file with mode: 0644]
src/WINNT/netidmgr_plugin/help/html/afsplhlp.css [new file with mode: 0644]
src/WINNT/netidmgr_plugin/help/html/bugs.htm [new file with mode: 0644]
src/WINNT/netidmgr_plugin/help/html/config_service.htm [new file with mode: 0644]
src/WINNT/netidmgr_plugin/help/html/copyright.htm [new file with mode: 0644]
src/WINNT/netidmgr_plugin/help/html/images/openafs-logo.jpg [new file with mode: 0644]
src/WINNT/netidmgr_plugin/help/html/images/window_cfg_afs_0.bmp [new file with mode: 0644]
src/WINNT/netidmgr_plugin/help/html/images/window_cfg_afs_main.bmp [new file with mode: 0644]
src/WINNT/netidmgr_plugin/help/html/images/window_nc_afs_0.bmp [new file with mode: 0644]
src/WINNT/netidmgr_plugin/help/html/images/window_nc_afs_1.bmp [new file with mode: 0644]
src/WINNT/netidmgr_plugin/help/html/images/window_nc_afs_2.bmp [new file with mode: 0644]
src/WINNT/netidmgr_plugin/help/html/images/window_nc_main.bmp [new file with mode: 0644]
src/WINNT/netidmgr_plugin/help/html/images/window_nc_prob.bmp [new file with mode: 0644]
src/WINNT/netidmgr_plugin/help/html/template.htm [new file with mode: 0644]
src/WINNT/netidmgr_plugin/help/html/token_methods.htm [new file with mode: 0644]
src/WINNT/netidmgr_plugin/help/html/tokens_per_id.htm [new file with mode: 0644]
src/WINNT/netidmgr_plugin/help/html/welcome.htm [new file with mode: 0644]
src/WINNT/netidmgr_plugin/help/popups_cfg.txt [new file with mode: 0644]
src/WINNT/netidmgr_plugin/help/popups_newcred.txt [new file with mode: 0644]
src/WINNT/netidmgr_plugin/help/toc.hhc [new file with mode: 0644]
src/WINNT/netidmgr_plugin/images/OpenAFS.ico [new file with mode: 0644]
src/WINNT/netidmgr_plugin/images/afstoken.ico [new file with mode: 0644]
src/WINNT/netidmgr_plugin/images/nc_exist.ico [new file with mode: 0644]
src/WINNT/netidmgr_plugin/images/nc_new.ico [new file with mode: 0644]
src/WINNT/netidmgr_plugin/images/nc_notowned.ico [new file with mode: 0644]
src/WINNT/netidmgr_plugin/krb5common.c [new file with mode: 0644]
src/WINNT/netidmgr_plugin/krb5common.h [new file with mode: 0644]
src/WINNT/netidmgr_plugin/lang/en_us/langres.rc [new file with mode: 0644]
src/WINNT/netidmgr_plugin/lang/en_us/license.rtf [new file with mode: 0644]
src/WINNT/netidmgr_plugin/lang/en_us/resource.h [new file with mode: 0644]
src/WINNT/netidmgr_plugin/langres.h [new file with mode: 0644]
src/WINNT/netidmgr_plugin/main.c [new file with mode: 0644]
src/WINNT/netidmgr_plugin/params.h [new file with mode: 0644]
src/WINNT/netidmgr_plugin/version.rc [new file with mode: 0644]
src/config/NTMakefile

index 42a6306..f6b59fb 100644 (file)
@@ -563,7 +563,14 @@ aklog: client_creds
        $(NTMAKE)
        $(CD) ..\..\..
 
-extra: aklog
+netidmgr_plugin: aklog
+     echo ***** $@
+       $(DOCD) $(SRC)\WINNT\$@
+       $(CD) $(SRC)\WINNT\$@
+       $(NTMAKE)
+       $(CD) ..\..\..
+
+extra: netidmgr_plugin
 !      IF EXIST($(SRC)\WINNT\extra) && EXIST($(SRC)\WINNT\extra\NTMakefile)
      echo ***** $@
     $(DOCD) $(SRC)\WINNT\$@
index a8823ec..2126146 100644 (file)
@@ -85,6 +85,7 @@ VIAddVersionKey "PrivateBuild" "Checked/Debug"
   !define AFS_COMPANY_NAME "OpenAFS"
   !define AFS_PRODUCT_NAME "OpenAFS"
   !define AFS_REGKEY_ROOT "Software\TransarcCorporation"
+  !define NID_PLUGIN_MGR  "Software\MIT\NetIDMgr\PluginManager"
   CRCCheck force
 
   ;Folder selection page
@@ -539,7 +540,7 @@ Section "!AFS Client" secClient
   File "${AFS_CLIENT_BUILDDIR}\afsdacl.exe"
   File "${AFS_CLIENT_BUILDDIR}\cmdebug.exe"
   File "${AFS_CLIENT_BUILDDIR}\aklog.exe"
-  File "${AFS_CLIENT_BUILDDIR}\afscreds.exe"
+  !insertmacro ReplaceDLL "${AFS_CLIENT_BUILDDIR}\afscreds.exe"           "$INSTDIR\Client\Program\afscreds.exe"    "$INSTDIR"
   !insertmacro ReplaceDLL "${AFS_CLIENT_BUILDDIR}\afs_shl_ext.dll" "$INSTDIR\Client\Program\afs_shl_ext.dll" "$INSTDIR"
   File "${AFS_CLIENT_BUILDDIR}\afsd_service.exe"
   File "${AFS_CLIENT_BUILDDIR}\symlink.exe"
@@ -553,6 +554,9 @@ Section "!AFS Client" secClient
   File "${AFS_DESTDIR}\etc\rxdebug.exe"
   File "${AFS_DESTDIR}\etc\backup.exe"
   !insertmacro ReplaceDLL "${AFS_CLIENT_BUILDDIR}\afs_cpa.cpl" "$INSTDIR\Client\Program\afs_cpa.cpl" "$INSTDIR"
+  !insertmacro ReplaceDLL "${AFS_CLIENT_BUILDDIR}\afscred.dll" "$INSTDIR\Client\Program\afscred.dll" "$INSTDIR"
+  !insertmacro ReplaceDLL "${AFS_CLIENT_BUILDDIR}\afscred_en_us.dll" "$INSTDIR\Client\Program\afscred_en_us.dll" "$INSTDIR"
+  File "${AFS_CLIENT_BUILDDIR}\afsplhlp.chm"
   
   SetOutPath "$SYSDIR"
   !insertmacro ReplaceDLL "${AFS_CLIENT_BUILDDIR}\afslogon.dll" "$SYSDIR\afslogon.dll" "$INSTDIR"
@@ -626,6 +630,18 @@ Section "!AFS Client" secClient
    DeleteRegValue HKLM "${AFS_REGKEY_ROOT}\AFS Client\${AFS_VERSION}" "Debug"
 !endif
 
+  ;NetIDMgr Plug-in Reg Entries
+  WriteRegStr HKLM "${NID_PLUGIN_MGR}\Modules\OpenAFS" "ImagePath" "$INSTDIR\Client\Program\afscred.dll"
+  WriteRegStr HKLM "${NID_PLUGIN_MGR}\Modules\OpenAFS" "Description" "OpenAFS Module"
+  WriteRegStr HKLM "${NID_PLUGIN_MGR}\Modules\OpenAFS" "Vendor" "Secure Endpoints Inc."
+  WriteRegStr HKLM "${NID_PLUGIN_MGR}\Modules\OpenAFS" "PluginList" "AfsCred"
+  WriteRegDWORD HKLM "${NID_PLUGIN_MGR}\Modules\OpenAFS" "NoUnload" "1"
+  
+  WriteRegStr HKLM "${NID_PLUGIN_MGR}\Plugins\AfsCred" "Module" "OpenAFS"
+  WriteRegStr HKLM "${NID_PLUGIN_MGR}\Plugins\AfsCred" "Description" "AFS Credentials Provider"
+  WriteRegStr HKLM "${NID_PLUGIN_MGR}\Plugins\AfsCred" "Dependencies" "Krb5Cred"
+  WriteRegDWORD HKLM "${NID_PLUGIN_MGR}\Plugins\AfsCred" "Type" "1"
+
    ; On Windows 2000 work around KB301673.  This is fixed in Windows XP and 2003
    Call GetWindowsVersion
    Pop $R1
@@ -1133,6 +1149,7 @@ Section /o "Debug symbols" secDebug
   File "${AFS_DESTDIR}\etc\rxdebug.pdb"
   File "${AFS_DESTDIR}\etc\backup.pdb"
   File "${AFS_CLIENT_BUILDDIR}\afs_cpa.pdb"
+  File "${AFS_CLIENT_BUILDDIR}\afscred.pdb"
 
   SetOutPath "$SYSDIR"
   File "${AFS_CLIENT_BUILDDIR}\afslogon.pdb"
@@ -1998,6 +2015,9 @@ StartRemove:
   DeleteRegKey HKLM "${AFS_REGKEY_ROOT}\AFS Server\CurrentVersion"
   DeleteRegKey HKLM "${AFS_REGKEY_ROOT}\AFS Server"
   DeleteRegKey /ifempty HKLM "${AFS_REGKEY_ROOT}"
+  DeleteRegKey HKLM "${NID_PLUGIN_MGR}\Modules\OpenAFS"
+  DeleteRegKey HKLM "${NID_PLUGIN_MGR}\Plugins\AfsCred"
+  DeleteRegKey /ifempty HKLM "Software\MIT\NetIDMgr"
   DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenAFS"
   DeleteRegValue HKLM "SYSTEM\CurrentControlSet\Services\NetBT\Parameters" "SmbDeviceEnabled"
 
index bb36097..684b68e 100644 (file)
                     <ComponentRef Id="rcm_Loopback"/>
                 </Feature>
 
-                               <Feature Id="feaKB301673" AllowAdvertise="no" Absent="disallow" Display="hidden" InstallDefault="followParent" Level="0">
-                                       <ComponentRef Id="rcm_KB301673" />
-                                       <Condition Level="30">VersionNT = 500 And ServicePackLevel &lt; 3</Condition>
-                               </Feature>
+  <?if $(env.CPU) = "i386"?>
+            <Feature Id="feaNetIDMgrPlugin" AllowAdvertise="no" Description="$(loc.StrNIDMPluginLongDesc)"
+                    Display="expand" InstallDefault="followParent" Level="30" Title="$(loc.StrNIDMPluginDesc)">
+                    <ComponentRef Id="_afscreds_plugin" />
+                    <ComponentRef Id="_afscreds_en_us" />
+                    <ComponentRef Id="_afscreds_chm" />
+           <?ifdef DebugSyms?>
+                    <Feature Id="DebugSyms" Title="$(loc.StrNIDMDebugDesc)" InstallDefault="$(var.DebugSymInstallDefault)"
+                       Level="$(var.DebugSymLowLevel)" Display="expand" Description="$(loc.StrNIDMDebugLongDesc)">
+                       <ComponentRef Id="_afscreds_debugsym" />
+                    </Feature>
+           <?endif?>
+            </Feature>
+  <?endif?>
+
+               <Feature Id="feaKB301673" AllowAdvertise="no" Absent="disallow" Display="hidden" InstallDefault="followParent" Level="0">
+                       <ComponentRef Id="rcm_KB301673" />
+                       <Condition Level="30">VersionNT = 500 And ServicePackLevel &lt; 3</Condition>
+               </Feature>
                                
-                               <Feature Id="feaCredsStartup" AllowAdvertise="no" Display="hidden" InstallDefault="followParent" Level="30">
-                                       <ComponentRef Id="cmp_credsStartup" />
-                                       <Condition Level="130">CREDSSTARTUP = 0</Condition>
-                               </Feature>
+               <Feature Id="feaCredsStartup" AllowAdvertise="no" Display="hidden" InstallDefault="followParent" Level="30">
+                       <ComponentRef Id="cmp_credsStartup" />
+                       <Condition Level="130">CREDSSTARTUP = 0</Condition>
+               </Feature>
                                
-                       <?ifdef DebugSyms?>
-                               <Feature Id="feaClientDebug" AllowAdvertise="no" Description="$(loc.StrAFSClientDebugLongDesc)" Display="expand"
-                                       InstallDefault="$(var.DebugSymInstallDefault)" Level="$(var.DebugSymLowLevel)" Title="$(loc.StrAFSClientDebugDesc)">
-                    <ComponentRef Id="cmp_ClientProgramDebug" />
-                    <ComponentRef Id="cmp_CommonCommonDebug" />
-                    <ComponentRef Id="cmp_ClientCommonDebug" />
-                    <ComponentRef Id="cmp_ClientSystemDebug" />
-                    <?include runtime_debug.wxi?>
-                               </Feature>
-                       <?endif?>
+               <?ifdef DebugSyms?>
+                       <Feature Id="feaClientDebug" AllowAdvertise="no" Description="$(loc.StrAFSClientDebugLongDesc)" Display="expand"
+                               InstallDefault="$(var.DebugSymInstallDefault)" Level="$(var.DebugSymLowLevel)" Title="$(loc.StrAFSClientDebugDesc)">
+                               <ComponentRef Id="cmp_ClientProgramDebug" />
+                               <ComponentRef Id="cmp_CommonCommonDebug" />
+                               <ComponentRef Id="cmp_ClientCommonDebug" />
+                               <ComponentRef Id="cmp_ClientSystemDebug" />
+                               <?include runtime_debug.wxi?>
+                       </Feature>
+               <?endif?>
 
-                               <ComponentRef Id="rcm_Client" />
+               <ComponentRef Id="rcm_Client" />
                 <ComponentRef Id="rcm_ClientCacheSize" />
                 <ComponentRef Id="rcm_ClientCachePath" />
                 <ComponentRef Id="rcm_StoreAnsiFilenames" />
 
-                               <ComponentRef Id="cmp_CommonDir" />
+               <ComponentRef Id="cmp_CommonDir" />
 
                 <ComponentRef Id="efl_Readme_TXT_$(var.Language)" />
                 <ComponentRef Id="efl_CellServDB" />
             <Feature Id="feaBinaries" AllowAdvertise="no" Description="$(loc.StrBinsOnlyLongDesc)"
                 Display="expand" InstallDefault="followParent" Level="100" Title="$(loc.StrBinsOnlyDesc)">
 
-                       <?ifdef DebugSyms?>
-                               <Feature Id="feaClientDebug" AllowAdvertise="no" Description="$(loc.StrAFSClientDebugLongDesc)" Display="expand"
-                                       InstallDefault="$(var.DebugSymInstallDefault)" Level="$(var.DebugSymLowLevel)" Title="$(loc.StrAFSClientDebugDesc)">
+               <?ifdef DebugSyms?>
+                       <Feature Id="feaClientDebug" AllowAdvertise="no" Description="$(loc.StrAFSClientDebugLongDesc)" Display="expand"
+                               InstallDefault="$(var.DebugSymInstallDefault)" Level="$(var.DebugSymLowLevel)" Title="$(loc.StrAFSClientDebugDesc)">
                     <ComponentRef Id="cmp_ClientProgramDebug" />
                     <ComponentRef Id="cmp_CommonCommonDebug" />
                     <?include runtime_debug.wxi?>
                                </Feature>
                        <?endif?>
 
-                               <ComponentRef Id="cmp_CommonDir" />
+  <?if $(env.CPU) = "i386"?>
+            <Feature Id="feaNetIDMgrPlugin" AllowAdvertise="no" Description="$(loc.StrNIDMPluginLongDesc)"
+                    Display="expand" InstallDefault="followParent" Level="30" Title="$(loc.StrNIDMPluginDesc)">
+                    <ComponentRef Id="_afscreds_plugin" />
+                    <ComponentRef Id="_afscreds_en_us" />
+                    <ComponentRef Id="_afscreds_chm" />
+           <?ifdef DebugSyms?>
+                    <Feature Id="DebugSyms" Title="$(loc.StrNIDMDebugDesc)" InstallDefault="$(var.DebugSymInstallDefault)"
+                       Level="$(var.DebugSymLowLevel)" Display="expand" Description="$(loc.StrNIDMDebugLongDesc)">
+                       <ComponentRef Id="_afscreds_debugsym" />
+                    </Feature>
+           <?endif?>
+            </Feature>
+  <?endif?>
+
+               <ComponentRef Id="cmp_CommonDir" />
 
                 <ComponentRef Id="cmf_afsrpc_DLL" />
                 <ComponentRef Id="cmf_afsauthent2_DLL" />
index 3d34d2a..9959d17 100644 (file)
                         <File Id="fileafs_shl_ext_1033_DLL" Name="ashl1033.dll" LongName="afs_shl_ext_1033.dll" KeyPath="yes" DiskId="1" src="$(var.ClientDir)\afs_shl_ext_1033.dll"/>
                     </Component>
 
+  <?if $(env.CPU)="i386"?>
+                    <Component Win64="$(var.Win64)" Id="_afscreds_en_us"
+                        Guid="$(var._afscreds_en_us_guid)" DiskId="1">
+                        <File Id="file_afscred_en_us_dll" Name="afscenu.dll" LongName="afscred_en_us.dll" KeyPath="yes"/>
+                    </Component>
+
+                    <Component Win64="$(var.Win64)" Id="_afscreds_plugin" 
+                        Guid="$(var._afscreds_plugin_guid)" DiskId="1">
+                        <File Id="file_afscred_dll" Name="afscred.dll" LongName="afscred.dll" KeyPath="yes"/>
+                        <Registry Id="reg_mod_01" Root="HKLM" Key="SOFTWARE\MIT\NetIDMgr\PluginManager\Modules\OpenAFS" Action="createKeyAndRemoveKeyOnUninstall" />
+                        <Registry Id="reg_mod_02" Root="HKLM" Key="SOFTWARE\MIT\NetIDMgr\PluginManager\Modules\OpenAFS" />
+                        <Registry Id="reg_mod_03" Root="HKLM" Key="SOFTWARE\MIT\NetIDMgr\PluginManager\Modules\OpenAFS" Name="ImagePath" Type="string" Value="[#file_afscred_dll]" />
+                        <Registry Id="reg_mod_04" Root="HKLM" Key="SOFTWARE\MIT\NetIDMgr\PluginManager\Modules\OpenAFS" Name="Description" Type="string" Value="OpenAFS Module" />
+                        <Registry Id="reg_mod_05" Root="HKLM" Key="SOFTWARE\MIT\NetIDMgr\PluginManager\Modules\OpenAFS" Name="Vendor" Type="string" Value="Secure Endpoints Inc." />
+                        <Registry Id="reg_mod_06" Root="HKLM" Key="SOFTWARE\MIT\NetIDMgr\PluginManager\Modules\OpenAFS" Name="PluginList" Type="string" Value="AfsCred" />
+                        <Registry Id="reg_mod_07" Root="HKLM" Key="SOFTWARE\MIT\NetIDMgr\PluginManager\Modules\OpenAFS" Name="NoUnload" Type="integer" Value="1" />
+                        <Registry Id="reg_plg_01" Root="HKLM" Key="SOFTWARE\MIT\NetIDMgr\PluginManager\Plugins\AfsCred" Action="createKeyAndRemoveKeyOnUninstall" />
+                        <Registry Id="reg_plg_02" Root="HKLM" Key="SOFTWARE\MIT\NetIDMgr\PluginManager\Plugins\AfsCred" />
+                        <Registry Id="reg_plg_03" Root="HKLM" Key="SOFTWARE\MIT\NetIDMgr\PluginManager\Plugins\AfsCred" Name="Module" Type="string" Value="OpenAFS" />
+                        <Registry Id="reg_plg_04" Root="HKLM" Key="SOFTWARE\MIT\NetIDMgr\PluginManager\Plugins\AfsCred" Name="Description" Type="string" Value="AFS Credentials Provider" />
+                        <Registry Id="reg_plg_05" Root="HKLM" Key="SOFTWARE\MIT\NetIDMgr\PluginManager\Plugins\AfsCred" Name="Dependencies" Type="string" Value="Krb5Cred" />
+                        <Registry Id="reg_plg_06" Root="HKLM" Key="SOFTWARE\MIT\NetIDMgr\PluginManager\Plugins\AfsCred" Name="Type" Type="integer" Value="1" />
+                    </Component>
+  
+     <?ifdef DebugSyms?>            
+                    <Component Win64="$(var.Win64)" Id="_afscreds_debugsym"
+                        Guid="$(var._afscreds_debugsym_guid)" DiskId="1">
+                        <File Id="file_afscred_pdb" Name="afscred.pdb" LongName="afscred.pdb" KeyPath="yes"/>
+                    </Component>
+     <?endif?>
+                    <Component Id="_afscreds_chm"
+                        Guid="$(var._afscreds_chm_guid)" DiskId="1">
+                        <File Id="file_afsplhlp_chm" Name="afsplhlp.chm" LongName="afsplhlp.chm" KeyPath="yes" />
+                    </Component>
+  <?endif?>
+
   <?ifndef BinsOnly ?>
                     <Component Win64="$(var.Win64)" Id="cmf_afsd_service_EXE" Guid="$(var.cmf_afsd_service_EXE_guid)">
                         <File Id="fileafsd_service_EXE" Name="afsd_svc.exe" LongName="afsd_service.exe" KeyPath="yes" DiskId="1" />
index 72a2843..5737a82 100644 (file)
     <String Id="StrLoopbackLongDesc">Loopback adapter for AFS.  It is recommended that you install the loopback adapter if you are installing the client components.</String>
     <String Id="StrBinsOnlyLongDesc">OpenAFS command-line utilities and libraries.</String>
     <String Id="StrBinsOnlyDesc">Tools and libraries</String>
+    <String Id="StrNIDMPluginDesc">NetIDMgr Plug-in</String>
+    <String Id="StrNIDMPluginLongDesc">OpenAFS plug-in for Network Identity Manager. Adds AFS token management capabilities to Network Identity Manager.</String>
+    <String Id="StrNIDMDebugDesc">Debug symbols for NetIDMgr plug-in</String>
+    <String Id="StrNIDMDebugLongDesc">Debugging symbols for the OpenAFS NetIDMgr plug-in.</String>
 
     <String Id="StrShlExtDesc">AFS Context Menu Shell Extension</String>
     <String Id="StrAfsCredsDesc">Authentication for AFS</String>
index 933f2be..3fde40a 100644 (file)
         <AdvertiseExecuteSequence />
         <AdminExecuteSequence />
         <InstallExecuteSequence>
-                       <RemoveExistingProducts After="InstallValidate">IBMAFS_UPGRADE OR OPENAFS_UPGRADE</RemoveExistingProducts>
+                       <RemoveExistingProducts After="InstallValidate">IBMAFS_UPGRADE OR OPENAFS_UPGRADE OR AFSPLUGIN_UPGRADE</RemoveExistingProducts>
                        <Custom Action="RemoveNsisInstallation" Before="AbortInstallationA">NSISUNINSTALL &lt;&gt; "" AND UILevel &gt;= 4</Custom>
                        <Custom Action="AbortInstallationA" Before="CostInitialize">NSISUNINSTALL &lt;&gt; "" AND UILevel &lt; 4</Custom>
                        <!-- Assert that if the server is going to be installed locally after this session, control center and client are also local -->
             <UpgradeVersion IgnoreRemoveFailure="no" IncludeMaximum="yes" Maximum="3.6.2" MigrateFeatures="no" Property="IBMAFS_UPGRADE" />
         </Upgrade>
         
+  <?if $(env.CPU) = "i386" ?>
+        <!-- Secure-Endpoints OpenAFS NetIDMgr plug-in -->
+        <Upgrade Id="646D643A-73E3-4C77-AE4A-EDBE313DD45D">
+            <UpgradeVersion IgnoreRemoveFailure="no" IncludeMaximum="no" Maximum="$(var.NumericVersion)" MigrateFeatures="no" Property="AFSPLUGIN_UPGRADE" />
+        </Upgrade>
+  <?endif?>
+        
         <!-- openafs.org NSIS installer is detected using other means -->
         <!-- Please let us know if you want other Installers to be detected and upgraded/removed -->
 
index e8b1d8f..53ccc92 100644 (file)
        <?define cmp_Server_Program_Debug_guid="5F7BA9F7-E9BD-4AC3-9232-5EFBF6B740F8"?>
         <?define rcm_binsonly_parm_guid="4DFE834A-F129-4FDD-91AD-8A31A849AF0B"?>
         <?define clsid_afs_shl_ext="DC515C27-6CAC-11D1-BAE7-00C04FD140D2"?>
-
+        <?define _afscreds_en_us_guid="B7F72D5F-B8A2-4FE8-B675-71BA4D04FA5C"?>
+        <?define _afscreds_plugin_guid="3477A7C4-9BC9-4AF9-B97D-C96455CC3AF6"?>
+        <?define _afscreds_debugsym_guid="DCBE9170-746F-4894-96FA-B8441A133133"?>
+        <?define _afscreds_chm_guid="11657F75-67AD-4DBA-8344-BF65B7CCAAD2"?>
 <?else?>
        <?error Unknown platform?>
 <?endif?>
diff --git a/src/WINNT/netidmgr_plugin/NTMakefile b/src/WINNT/netidmgr_plugin/NTMakefile
new file mode 100644 (file)
index 0000000..ba84673
--- /dev/null
@@ -0,0 +1,183 @@
+#
+# Copyright (c) 2005,2006 Secure Endpoints Inc.
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation files
+# (the "Software"), to deal in the Software without restriction,
+# including without limitation the rights to use, copy, modify, merge,
+# publish, distribute, sublicense, and/or sell copies of the Software,
+# and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+AFSDEV_AUXRCFLAGS=/i ..\kfw\inc\netidmgr
+RELDIR=WINNT\netidmgr_plugin
+!INCLUDE ..\..\config\NTMakefile.$(SYS_NAME)
+!INCLUDE ..\..\config\NTMakefile.version
+
+AFSPLUGIN_VERSION_MAJOR=$(AFSPRODUCT_VER_MAJOR)
+AFSPLUGIN_VERSION_MINOR=$(AFSPRODUCT_VER_MINOR)
+AFSPLUGIN_VERSION_PATCH=$(AFSPRODUCT_VER_PATCH)
+AFSPLUGIN_VERSION_AUX  =$(AFSPRODUCT_VER_BUILD)
+
+AFSPLUGIN_VERSION=$(AFSPLUGIN_VERSION_MAJOR).$(AFSPLUGIN_VERSION_MINOR).$(AFSPLUGIN_VERSION_PATCH).$(AFSPLUGIN_VERSION_AUX)
+AFSPLUGIN_VERLIST=$(AFSPLUGIN_VERSION_MAJOR),$(AFSPLUGIN_VERSION_MINOR),$(AFSPLUGIN_VERSION_PATCH),$(AFSPLUGIN_VERSION_AUX)
+
+# short form version numbers
+TAFSPLUGIN_VERSION=$(AFSPLUGIN_VERSION_MAJOR).$(AFSPLUGIN_VERSION_MINOR).$(AFSPLUGIN_VERSION_PATCH)
+
+# Directories
+
+EXEDIR = $(DESTDIR)\root.client\usr\vice\etc
+
+INCFILEDIR = $(DESTDIR)\include\WINNT
+
+LIBFILEDIR = $(DESTDIR)\lib
+
+KFWINCDIR = ..\kfw\inc
+
+KFWLIBDIR = ..\kfw\lib\$(CPU)
+
+# Build environment
+
+kfwincflags=-I$(KFWINCDIR)\krb5\KerberosIV -I$(KFWINCDIR)\loadfuncs -I$(KFWINCDIR)\krb5 -I$(KFWINCDIR)\netidmgr -I$(KFWINCDIR)
+afsincflags=-I$(DESTDIR)\include
+
+incflags=$(kfwincflags) $(afsincflags) -I.
+pldefines=-DUNICODE -D_UNICODE
+cdebug=$(cdebug) -Os -Zi
+cwarn=$(cwarn) /Wp64 /WX
+
+plcflags=$(cdebug) $(cflags) $(incflags) $(pldefines) $(cwarn) $(cvarsmt)
+
+PC2OBJ=$(CC) $(plcflags) /Fo"$@" /c $**
+
+{}.c{$(OBJ)}.obj:
+       $(PC2OBJ)
+
+# Targets
+
+CHMFILE=$(EXEDIR)\afsplhlp.chm
+
+DLLFILE=$(EXEDIR)\afscred.dll
+
+LIBFILE=$(LIBFILEDIR)\afscred.lib
+
+INCFILES=                              \
+       $(INCFILEDIR)\afspext.h         \
+       $(INCFILEDIR)\afsp_version.h
+
+OBJFILES=                              \
+       $(OUT)\afsfuncs.obj             \
+       $(OUT)\afsplugin.obj            \
+       $(OUT)\main.obj                 \
+       $(OUT)\afsconfig.obj            \
+       $(OUT)\afsconfigdlg.obj         \
+       $(OUT)\afsnewcreds.obj          \
+       $(OUT)\afsext.obj               \
+       $(OUT)\afshelp.obj              \
+       $(OUT)\dynimport.obj            \
+       $(OUT)\krb5common.obj
+
+LIBFILES=                              \
+       $(KFWLIBDIR)\nidmgr32.lib
+
+SDKLIBFILES=                           \
+       $(DESTDIR)\lib\afsauthent.lib   \
+       $(DESTDIR)\lib\libafsconf.lib   \
+       $(KFWLIBDIR)\loadfuncs.lib      \
+       htmlhelp.lib                    \
+       shell32.lib                     \
+       comctl32.lib                    \
+       version.lib                     \
+       shlwapi.lib                     \
+       psapi.lib
+
+VERRESFILE=$(OUT)\version.res
+
+$(OUT)\afsfuncs.obj: afsfuncs.c
+       $(PC2OBJ)
+
+$(OUT)\afsplugin.obj: afsplugin.c
+       $(PC2OBJ)
+
+$(OUT)\main.obj: main.c
+       $(PC2OBJ)
+
+$(OUT)\afsconfig.obj: afsconfig.c
+       $(PC2OBJ)
+
+$(OUT)\afsconfigdlg.obj: afsconfigdlg.c
+       $(PC2OBJ)
+
+$(OUT)\afsnewcreds.obj: afsnewcreds.c
+       $(PC2OBJ)
+
+$(OUT)\afsext.obj: afsext.c
+       $(PC2OBJ)
+
+$(OUT)\afshelp.obj: afshelp.c
+       $(PC2OBJ)
+
+$(OUT)\dynimport.obj: dynimport.c
+       $(PC2OBJ)
+
+$(OUT)\krb5common.obj: krb5common.c
+       $(PC2OBJ)
+
+!include afsp_version.h.in
+
+$(DLLFILE): $(OBJFILES) $(VERRESFILE)
+       $(DLLGUILINK) $(LIBFILES) $(SDKLIBFILES)
+       $(_VC_MANIFEST_EMBED_DLL)
+       $(_VC_MANIFEST_CLEAN)
+
+dummy:
+
+$(CHMFILE): dummy
+       $(CD) help
+       nmake /f NTMakefile install
+       $(CD) ..
+
+install: $(INCFILES) $(CHMFILE) $(DLLFILE) lang
+
+lang::
+
+# Repeat this block as necessary redefining LANG for additional
+# languages.
+
+# Begin language block
+LANG=en_us
+
+LANGDLL=$(EXEDIR)\afscred_$(LANG).dll
+
+lang:: $(LANGDLL)
+
+$(LANGDLL): $(OUT)\langres_$(LANG).res $(OUT)\langres_ver_$(LANG).res
+       $(DLLRESLINK)
+
+$(OUT)\langres_ver_$(LANG).res: version.rc
+       $(RC) /d LANGVER /d LANG_$(LANG) /fo $@ $** 
+
+$(OUT)\langres_$(LANG).res: lang\$(LANG)\langres.rc
+       $(RC) /fo $@ $**
+# End language block
+
+clean::
+!ifdef INCFILES
+       $(DEL) $(INCFILES)
+!endif
+       $(CD) help
+       $(MAKECMD) /f NTMakefile clean
+       $(CD) ..
diff --git a/src/WINNT/netidmgr_plugin/afsconfig.c b/src/WINNT/netidmgr_plugin/afsconfig.c
new file mode 100644 (file)
index 0000000..512e2a0
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+This file was autogenerated from:
+    c:\work\pismere\athena\auth\krb5\src\windows\identity\config\csvschema.cfg
+    afsconfig.csv
+
+Do not modify directly.
+*/
+#include<kconfig.h>
+
+kconf_schema schema_afsconfig[] = {
+{L"AfsCred",KC_SPACE,0,L"AFS Credentials Provider"},
+{L"Module",KC_STRING,(khm_int64) L"OpenAFS",L""},
+{L"Description",KC_STRING,(khm_int64) L"AFS Credentials Provider",L""},
+{L"Dependencies",KC_STRING,(khm_int64) L"Krb5Cred",L""},
+{L"Type",KC_INT32,1,L""},
+{L"Flags",KC_INT32,0,L""},
+{L"Cells",KC_STRING,(khm_int64) L"",L"Multi string giving list of cells to authenticate to"},
+{L"Disableafscreds",KC_INT32,0,L"Disable afscreds.exe"},
+{L"Parameters",KC_SPACE,0,L"Parameters for AfsCred"},
+{L"AFSEnabled",KC_INT32,1,L"Is AFS enabled?"},
+{L"LRUCells",KC_STRING,(khm_int64) L"",L"List of recently used cells"},
+{L"LRURealms",KC_STRING,(khm_int64) L"",L"List of recently used realms"},
+{L"DefaultCells",KC_STRING,(khm_int64) L"",L"List of default cells to authenticate to."},
+{L"Parameters",KC_ENDSPACE,0,L""},
+{L"Cells",KC_SPACE,0,L"Per identity cells list and plugin settings"},
+{L"cellname",KC_STRING,(khm_int64) L"identity",L"Cell-identity mapping kept in the plugin configuration for the user."},
+{L"_Schema",KC_SPACE,0,L"Schema is named for each cell to authenticate"},
+{L"MethodName",KC_STRING,(khm_int64) L"",L"Name of method"},
+{L"Method",KC_INT32,0,L"(Deprecated) Method identifier"},
+{L"Realm",KC_STRING,(khm_int64) L"",L"Kerberos realm to use for authentication"},
+{L"_Schema",KC_ENDSPACE,0,L""},
+{L"Cells",KC_ENDSPACE,0,L""},
+{L"AfsCred",KC_ENDSPACE,0,L""}
+};
+
+
diff --git a/src/WINNT/netidmgr_plugin/afsconfigdlg.c b/src/WINNT/netidmgr_plugin/afsconfigdlg.c
new file mode 100644 (file)
index 0000000..1fbf84b
--- /dev/null
@@ -0,0 +1,646 @@
+/*
+ * Copyright (c) 2004 Massachusetts Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* $Id$ */
+
+#include<afscred.h>
+#include<kherror.h>
+#include<khuidefs.h>
+#include<commctrl.h>
+#include<help/afsplhlp.h>
+#include<htmlhelp.h>
+
+/* disable the 'name was marked as deprecated' warnings.  These get
+   issued for Str?Cat? and Str?Cpy? functions.  We don't use those
+   anyway. */
+#pragma warning(push)
+#pragma warning(disable: 4995)
+#include<shlwapi.h>
+#include<shlobj.h>
+#pragma warning(pop)
+
+#include<assert.h>
+
+typedef struct tag_afs_ids_dlg_data {
+    khui_config_init_data cfg;
+
+    khm_boolean afs_enabled;
+} afs_ids_dlg_data;
+
+INT_PTR CALLBACK
+afs_cfg_ids_proc(HWND hwnd,
+                 UINT uMsg,
+                 WPARAM wParam,
+                 LPARAM lParam) {
+
+    afs_ids_dlg_data * d = NULL;
+
+    switch(uMsg) {
+    case WM_INITDIALOG:
+        {
+            khm_int32 t = 1;
+
+            d = PMALLOC(sizeof(*d));
+            ZeroMemory(d, sizeof(*d));
+
+#pragma warning(push)
+#pragma warning(disable: 4244)
+            SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) d);
+#pragma warning(pop)
+
+            d->cfg = *((khui_config_init_data *) lParam);
+
+            khc_read_int32(csp_params, L"AFSEnabled", &t);
+
+            d->afs_enabled = !!t;
+
+            CheckDlgButton(hwnd, IDC_CFG_OBTAIN,
+                           (d->afs_enabled)? BST_CHECKED: BST_UNCHECKED);
+        }
+        return FALSE;
+
+    case WM_DESTROY:
+        {
+            d = (afs_ids_dlg_data *) (LONG_PTR)
+                GetWindowLongPtr(hwnd, DWLP_USER);
+
+            PFREE(d);
+        }
+        return TRUE;
+
+    case WM_COMMAND:
+        {
+            d = (afs_ids_dlg_data *) (LONG_PTR)
+                GetWindowLongPtr(hwnd, DWLP_USER);
+
+            if (wParam == MAKEWPARAM(IDC_CFG_OBTAIN, BN_CLICKED)) {
+                d->afs_enabled =
+                    (IsDlgButtonChecked(hwnd, IDC_CFG_OBTAIN) ==
+                     BST_CHECKED);
+                khui_cfg_set_flags_inst(&d->cfg, KHUI_CNFLAG_MODIFIED,
+                                        KHUI_CNFLAG_MODIFIED);
+                return TRUE;
+            }
+        }
+        return FALSE;
+
+    case KHUI_WM_CFG_NOTIFY:
+        {
+            d = (afs_ids_dlg_data *) (LONG_PTR)
+                GetWindowLongPtr(hwnd, DWLP_USER);
+
+            if (HIWORD(wParam) == WMCFG_APPLY) {
+                khm_int32 t;
+
+                if (KHM_FAILED(khc_read_int32(csp_params,
+                                              L"AFSEnabled", &t)) ||
+                    !!t != !!d->afs_enabled) {
+                    khc_write_int32(csp_params, L"AFSEnabled",
+                                    !!d->afs_enabled);
+
+                    khui_cfg_set_flags_inst(&d->cfg,
+                                            KHUI_CNFLAG_APPLIED,
+                                            KHUI_CNFLAG_APPLIED |
+                                            KHUI_CNFLAG_MODIFIED);
+                } else {
+                    khui_cfg_set_flags_inst(&d->cfg,
+                                            0,
+                                            KHUI_CNFLAG_MODIFIED);
+                }
+            }
+        }
+        return TRUE;
+    }
+
+    return FALSE;
+}
+
+INT_PTR CALLBACK
+afs_cfg_id_proc(HWND hwnd,
+                UINT uMsg,
+                WPARAM wParam,
+                LPARAM lParam) {
+
+    switch(uMsg) {
+
+    case WM_INITDIALOG:
+        {
+            INT_PTR rv;
+            afs_dlg_data * d;
+            wchar_t idname[KCDB_IDENT_MAXCCH_NAME];
+            khm_size cb;
+
+            rv = afs_dlg_proc(hwnd, uMsg, wParam, 0);
+
+            d = (afs_dlg_data *) (LONG_PTR) GetWindowLongPtr(hwnd, DWLP_USER);
+
+            d->cfg = *((khui_config_init_data *) lParam);
+
+            idname[0] = L'\0';
+            cb = sizeof(idname);
+            khui_cfg_get_name(d->cfg.ctx_node, idname, &cb);
+
+            d->ident = NULL;
+            kcdb_identity_create(idname, 0, &d->ident);
+
+#ifdef DEBUG
+            assert(d->ident);
+#endif
+
+            d->config_dlg = TRUE;
+
+            afs_cred_get_identity_creds(&d->creds, d->ident, &d->afs_enabled);
+
+            afs_dlg_proc(hwnd, KHUI_WM_NC_NOTIFY,
+                         MAKEWPARAM(0, WMNC_DIALOG_SETUP), 0);
+
+            return rv;
+        }
+        break;                  /* not reached */
+
+    case WM_DESTROY:
+        {
+            afs_dlg_data * d;
+
+            d = (afs_dlg_data *) (LONG_PTR) GetWindowLongPtr(hwnd, DWLP_USER);
+#ifdef DEBUG
+            assert(d && d->ident);
+#endif
+            kcdb_identity_release(d->ident);
+
+            return afs_dlg_proc(hwnd, uMsg, wParam, lParam);
+        }
+        break;                  /* not reached */
+
+    case KHUI_WM_CFG_NOTIFY:
+        {
+            afs_dlg_data * d;
+
+            d = (afs_dlg_data *) (LONG_PTR) GetWindowLongPtr(hwnd, DWLP_USER);
+
+            if (HIWORD(wParam) == WMCFG_APPLY) {
+                afs_cred_write_ident_data(d);
+            }
+        }
+        return TRUE;
+
+    default:
+        return afs_dlg_proc(hwnd, uMsg, wParam, lParam);
+    }
+}
+
+static void
+set_service_status(HWND hwnd) {
+    static DWORD wait_start = 0;
+    DWORD status = 0;
+    DWORD wait_hint = 0;
+    int i;
+    wchar_t status_strings_csv[1024];
+    wchar_t status_strings_ms[1024];
+    khm_size cb;
+    wchar_t *t;
+
+    GetServiceStatus(NULL,
+                     TRANSARCAFSDAEMON,
+                     &status, &wait_hint);
+
+    LoadString(hResModule, IDS_CFG_SVCSTATUS,
+               status_strings_csv, ARRAYLENGTH(status_strings_csv));
+
+    cb = sizeof(status_strings_ms);
+    csv_to_multi_string(status_strings_ms, &cb, status_strings_csv);
+
+    for(i=0, t = status_strings_ms; t && *t && *t != L' ';
+        t = multi_string_next(t), i++) {
+        if (i == status)
+            break;
+    }
+
+    if (!t || !*t)
+        t = status_strings_ms;  /* the first one is "unknown". */
+
+    SetDlgItemText(hwnd, IDC_CFG_STATUS, t);
+
+    if (status != SERVICE_RUNNING) {
+        HWND hw;
+
+        hw = GetDlgItem(hwnd, IDC_CFG_STOP);
+        if (hw == GetFocus())
+            SetFocus(GetNextDlgTabItem(hwnd, hw, FALSE));
+
+        EnableWindow(hw, FALSE);
+    } else {
+        EnableWindow(GetDlgItem(hwnd, IDC_CFG_STOP), TRUE);
+    }
+
+    if (status != SERVICE_STOPPED &&
+        status != SERVICE_PAUSED) {
+        HWND hw;
+
+        hw = GetDlgItem(hwnd, IDC_CFG_START);
+        if (hw == GetFocus())
+            SetFocus(GetNextDlgTabItem(hwnd, hw, FALSE));
+
+        EnableWindow(hw, FALSE);
+    } else {
+        EnableWindow(GetDlgItem(hwnd, IDC_CFG_START), TRUE);
+    }
+
+    if (status == SERVICE_START_PENDING ||
+        status == SERVICE_STOP_PENDING) {
+        HWND hw;
+        DWORD now;
+        int progress;
+
+        hw = GetDlgItem(hwnd, IDC_CFG_PROGRESS);
+#ifdef DEBUG
+        assert(hw);
+#endif
+        if (!IsWindowVisible(hw))
+            ShowWindow(hw, SW_SHOW);
+
+        if (wait_start == 0)
+            wait_start = GetTickCount();
+
+        now = GetTickCount();
+
+        if (now + wait_hint != wait_start)
+            progress = (now - wait_start) * 100 /
+                (now + wait_hint - wait_start);
+        else
+            progress = 0;
+
+        SendMessage(hw, PBM_SETPOS, progress, 0);
+
+        SetTimer(hwnd, 1, 500, NULL);
+    } else {
+        HWND hw;
+
+        hw = GetDlgItem(hwnd, IDC_CFG_PROGRESS);
+#ifdef DEBUG
+        assert(hw);
+#endif
+        wait_start = 0;
+        if (IsWindowVisible(hw))
+            ShowWindow(hw, SW_HIDE);
+    }
+}
+
+void
+afs_cfg_show_last_error(HWND hwnd, wchar_t * prefix, DWORD code) {
+    DWORD r;
+    wchar_t * err_desc = NULL;
+    wchar_t title[64];
+    wchar_t msg[1024];
+    wchar_t tmp[128];
+
+    r = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+                      FORMAT_MESSAGE_IGNORE_INSERTS |
+                      FORMAT_MESSAGE_FROM_SYSTEM,
+                      NULL,
+                      code,
+                      0,
+                      (LPWSTR) &err_desc,
+                      0,
+                      NULL);
+
+    if (r == 0 || err_desc == NULL)
+        return;
+
+    LoadString(hResModule, IDS_PLUGIN_DESC,
+               title, ARRAYLENGTH(title));
+    if (prefix == NULL)
+        tmp[0] = L'\0';
+    else if (IS_INTRESOURCE(prefix))
+        LoadString(hResModule, (UINT)(UINT_PTR) prefix,
+                   tmp, ARRAYLENGTH(tmp));
+    else
+        StringCbCopy(tmp, sizeof(tmp), prefix);
+
+    StringCbPrintf(msg, sizeof(msg), L"%s%s",
+                   tmp, err_desc);
+
+    MessageBox(hwnd, msg, title, MB_OK | MB_APPLMODAL);
+
+    LocalFree(err_desc);
+}
+
+#define SCNAME_AFSCREDS L"AFS Credentials.lnk"
+
+BOOL
+afs_cfg_get_afscreds_shortcut(wchar_t * wpath) {
+    HRESULT hr;
+    BOOL shortcut_found = FALSE;
+
+    hr = SHGetFolderPath(NULL, CSIDL_COMMON_STARTUP,
+                         NULL, SHGFP_TYPE_CURRENT,
+                         wpath);
+    if (FAILED(hr))
+        goto _noshortcut;
+
+    if (!PathAppend(wpath, SCNAME_AFSCREDS)) {
+        goto _noshortcut;
+    }
+
+    if (PathFileExists(wpath)) {
+        shortcut_found = TRUE;
+    }
+
+ _noshortcut:
+
+    return shortcut_found;
+}
+
+INT_PTR CALLBACK
+afs_cfg_main_proc(HWND hwnd,
+                  UINT uMsg,
+                  WPARAM wParam,
+                  LPARAM lParam) {
+    switch(uMsg) {
+    case WM_INITDIALOG:
+        {
+            wchar_t imagepath[MAX_PATH];
+            wchar_t blockname[MAX_PATH];
+            HKEY service_key;
+            LONG l;
+            DWORD cb;
+            DWORD dummy;
+            LPVOID ver_info;
+            wchar_t * value;
+
+            struct LANGANDCODEPATH {
+                WORD wLanguage;
+                WORD wCodePage;
+            } *translations;
+
+#pragma warning(push)
+#pragma warning(disable: 4244)
+            SetWindowLongPtr(hwnd, DWLP_USER, (DWORD_PTR) lParam);
+#pragma warning(pop)
+
+            /* Try to figure out if afscreds.exe is on the startup
+               group for all users. */
+            {
+                khm_handle csp_afscred = NULL;
+                khm_int32 disable = FALSE;
+
+                if (KHM_SUCCEEDED(kmm_get_plugin_config(AFS_PLUGIN_NAME,
+                                                        0,
+                                                        &csp_afscred))) {
+
+                    khc_read_int32(csp_afscred, L"Disableafscreds",
+                                   &disable);
+
+                    khc_close_space(csp_afscred);
+                }
+
+                if (!disable) {
+                    CheckDlgButton(hwnd, IDC_CFG_STARTAFSCREDS,
+                                   BST_UNCHECKED);
+                } else {
+                    CheckDlgButton(hwnd, IDC_CFG_STARTAFSCREDS,
+                                   BST_CHECKED);
+                }
+            }
+
+            l = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+                             L"SYSTEM\\CurrentControlSet\\Services\\TransarcAFSDaemon",
+                             0,
+                             KEY_READ,
+                             &service_key);
+
+            if (l != ERROR_SUCCESS)
+                goto _set_status;
+
+            cb = sizeof(imagepath);
+            l = RegQueryValueEx(service_key,
+                                L"ImagePath",
+                                NULL, NULL,
+                                (LPBYTE) imagepath,
+                                &cb);
+            if (l != ERROR_SUCCESS)
+                goto _close_key;
+
+            PathUnquoteSpaces(imagepath);
+
+            dummy = 1;
+            cb = GetFileVersionInfoSize(imagepath, &dummy);
+            if (cb == 0 || dummy)
+                goto _close_key;
+
+            ver_info = malloc(cb);
+#ifdef DEBUG
+            assert(ver_info);
+#endif
+            if (!ver_info)
+                goto _close_key;
+
+            if (!GetFileVersionInfo(imagepath,
+                                    0, cb, ver_info))
+                goto _free_buffer;
+
+            cb = 0;
+            if (!VerQueryValue(ver_info, 
+                               L"\\VarFileInfo\\Translation",
+                               (LPVOID*) &translations,
+                               &cb) ||
+                cb == 0)
+                goto _free_buffer;
+
+            StringCbPrintf(blockname, sizeof(blockname),
+                           L"\\StringFileInfo\\%04x%04x\\FileVersion",
+                           translations[0].wLanguage,
+                           translations[0].wCodePage);
+
+            if (!VerQueryValue(ver_info,
+                               blockname,
+                               (LPVOID*) &value,
+                               &cb) ||
+                cb == 0)
+                goto _free_buffer;
+
+            SetDlgItemText(hwnd, IDC_CFG_VERSION, value);
+
+            StringCbPrintf(blockname, sizeof(blockname),
+                           L"\\StringFileInfo\\%04x%04x\\CompanyName",
+                           translations[0].wLanguage,
+                           translations[0].wCodePage);
+
+            if (!VerQueryValue(ver_info,
+                               blockname,
+                               (LPVOID*) &value,
+                               &cb) ||
+                cb == 0)
+                goto _free_buffer;
+
+            SetDlgItemText(hwnd, IDC_CFG_COMPANY, value);
+
+        _free_buffer:
+            free(ver_info);
+        _close_key:
+            RegCloseKey(service_key);
+        _set_status:
+            set_service_status(hwnd);
+        }
+        return FALSE;
+
+    case WM_COMMAND:
+        switch(wParam) {
+        case MAKEWPARAM(IDC_CFG_STOP, BN_CLICKED):
+            {
+                DWORD r;
+
+                r = ServiceControl(NULL, TRANSARCAFSDAEMON, SERVICE_STOPPED);
+
+                if (r)
+                    afs_cfg_show_last_error(hwnd,
+                                            MAKEINTRESOURCE(IDS_CFG_CANTSTOP),
+                                            r);
+                else
+                    set_service_status(hwnd);
+            }
+            break;
+
+        case MAKEWPARAM(IDC_CFG_START,BN_CLICKED):
+            {
+                DWORD r;
+                r = ServiceControl(NULL, TRANSARCAFSDAEMON, SERVICE_RUNNING);
+
+                if (r)
+                    afs_cfg_show_last_error(hwnd,
+                                            MAKEINTRESOURCE(IDS_CFG_CANTSTART),
+                                            r);
+                else
+                    set_service_status(hwnd);
+            }
+            break;
+
+        case MAKEWPARAM(IDC_CFG_CPL, BN_CLICKED):
+            if (32 >= (LRESULT) ShellExecute (NULL, NULL, 
+                                              L"AFS_CONFIG.EXE", NULL,
+                                              NULL, SW_SHOW)) {
+                MessageBox(NULL, 
+                           L"Can't find file AFS_CONFIG.EXE", 
+                           L"Error", MB_OK);
+            }
+            break;
+
+        case MAKEWPARAM(IDC_CFG_STARTAFSCREDS, BN_CLICKED):
+            {
+                khui_config_node node;
+
+                node = (khui_config_node) (DWORD_PTR)
+                    GetWindowLongPtr(hwnd, DWLP_USER);
+
+                khui_cfg_set_flags(node,
+                                   KHUI_CNFLAG_MODIFIED,
+                                   KHUI_CNFLAG_MODIFIED);
+            }
+            break;
+        }
+        return TRUE;
+
+    case KHUI_WM_CFG_NOTIFY:
+        {
+            if (HIWORD(wParam) == WMCFG_APPLY) {
+                wchar_t wpath[MAX_PATH];
+                int dlg_state;
+                khui_config_node node;
+                khm_handle csp_afscred = NULL;
+                khm_int32 disable = FALSE;
+
+                node = (khui_config_node) (DWORD_PTR)
+                    GetWindowLongPtr(hwnd, DWLP_USER);
+
+                kmm_get_plugin_config(AFS_PLUGIN_NAME, KHM_PERM_WRITE,
+                                      &csp_afscred);
+
+                if (csp_afscred)
+                    khc_read_int32(csp_afscred, L"Disableafscreds",
+                                   &disable);
+
+                dlg_state = IsDlgButtonChecked(hwnd, IDC_CFG_STARTAFSCREDS);
+
+                if (!!disable !=
+                    (dlg_state == BST_CHECKED)) {
+                    if (csp_afscred)
+                        khc_write_int32(csp_afscred,
+                                        L"Disableafscreds",
+                                        (dlg_state == BST_CHECKED));
+
+                    khui_cfg_set_flags(node,
+                                       KHUI_CNFLAG_APPLIED,
+                                       KHUI_CNFLAG_MODIFIED |
+                                       KHUI_CNFLAG_APPLIED);
+                } else {
+                    khui_cfg_set_flags(node, 0,
+                                       KHUI_CNFLAG_MODIFIED);
+                }
+
+                if (dlg_state == BST_CHECKED &&
+                    afs_cfg_get_afscreds_shortcut(wpath)) {
+
+                    DeleteFile(wpath);
+                }
+            }
+        }
+        return TRUE;
+
+    case WM_TIMER:
+        if (wParam == 1) {
+            KillTimer(hwnd, 1);
+            set_service_status(hwnd);
+        }
+        break;
+
+    case WM_DESTROY:
+        return FALSE;
+
+    case WM_HELP:
+        {
+            static const DWORD ctx_help[] = {
+                IDC_CFG_STATUS, IDH_SVCSTATUS,
+                IDC_CFG_STOP, IDH_SVCSTOP,
+                IDC_CFG_START, IDH_SVCSTART,
+                IDC_CFG_VERSION, IDH_SVCVERSION,
+                IDC_CFG_COMPANY, IDH_SVCCOMPANY,
+                IDC_CFG_CPL, IDH_SVCCPL,
+                IDC_CFG_STARTAFSCREDS, IDH_STARTAFSCREDS,
+                0
+            };
+
+            LPHELPINFO hlp;
+
+            hlp = (LPHELPINFO) lParam;
+
+            if (hlp->iContextType != HELPINFO_WINDOW)
+                break;
+
+            afs_html_help(hlp->hItemHandle, L"::/popups_cfg.txt",
+                          HH_TP_HELP_WM_HELP, (DWORD_PTR) ctx_help);
+        }
+        return TRUE;
+    }
+    return FALSE;
+}
diff --git a/src/WINNT/netidmgr_plugin/afscred.h b/src/WINNT/netidmgr_plugin/afscred.h
new file mode 100644 (file)
index 0000000..3dad7ab
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2004 Massachusetts Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* $Id$ */
+
+#ifndef __KHIMAIRA_AFSCRED_H
+#define __KHIMAIRA_AFSCRED_H
+
+#define _WINSOCKAPI_
+#include<windows.h>
+#include<time.h>
+
+#define KHERR_FACILITY L"AfsCred"
+#define KHERR_HMODULE hResModule
+#include<netidmgr.h>
+
+#include<langres.h>
+
+#include <afs/cm_config.h>
+#include <afs/stds.h>
+#include <afs/auth.h>
+#include <afs/ptserver.h>
+#include <afs/ptuser.h>
+
+#include<afspext.h>
+
+#include<afsfuncs.h>
+#include<afsnewcreds.h>
+
+#ifndef NOSTRSAFE
+#include<strsafe.h>
+#endif
+
+#define AFS_PLUGIN_NAME         L"AfsCred"
+#define AFS_CREDTYPE_NAME       L"AfsCred"
+
+#define AFS_PLUGIN_DEPS         L"Krb5Cred\0"
+
+#define KRB5_CREDTYPE_NAME      L"Krb5Cred"
+#define KRB4_CREDTYPE_NAME      L"Krb4Cred"
+
+#define AFS_TYPENAME_PRINCIPAL      L"AFSPrincipal"
+#define AFS_TYPENAME_METHOD         L"AFSTokenMethod"
+#define AFS_ATTRNAME_CLIENT_PRINC   L"AFSClientPrinc"
+#define AFS_ATTRNAME_SERVER_PRINC   L"AFSServerPrinc"
+#define AFS_ATTRNAME_CELL           L"AFSCell"
+#define AFS_ATTRNAME_METHOD         L"AFSMethod"
+#define AFS_ATTRNAME_REALM          L"AFSRealm"
+
+#define AFS_VALID_CELL_CHARS    L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-"
+#define AFS_VALID_REALM_CHARS   AFS_VALID_CELL_CHARS
+
+#define AFS_CONFIG_NODE_IDS     L"AfsIdentities"
+#define AFS_CONFIG_NODE_ID      L"AfsIdentity"
+#define AFS_CONFIG_NODE_MAIN    L"AfsOptions"
+
+#define AFS_HELPFILE            L"afsplhlp.chm"
+
+/* token acquisition methods provided by extensions begin with this
+   ID */
+#define AFS_TOKEN_USER          8
+
+void init_afs();
+void exit_afs();
+KHMEXP khm_int32 KHMAPI init_module(kmm_module h_module);
+KHMEXP khm_int32 KHMAPI exit_module(kmm_module h_module);
+
+/* globals */
+extern kmm_module h_khModule;
+extern HMODULE hResModule;
+extern HINSTANCE hInstance;
+
+extern khm_int32 afs_credtype_id;
+extern khm_int32 krb5_credtype_id;
+extern khm_int32 krb4_credtype_id;
+extern khm_int32 afs_msg_type_id;
+extern khm_handle afs_credset;
+
+extern khm_int32 afs_type_principal;
+extern khm_int32 afs_attr_client_princ;
+extern khm_int32 afs_attr_server_princ;
+extern khm_int32 afs_attr_cell;
+extern khm_int32 afs_attr_method;
+extern khm_int32 afs_attr_realm;
+
+/* Configuration spaces */
+#define CSNAME_PLUGINS      L"Plugins"
+#define CSNAME_AFSCRED      L"AfsCred"
+#define CSNAME_PARAMS       L"Parameters"
+
+extern khm_handle csp_plugins;
+extern khm_handle csp_afscred;
+extern khm_handle csp_params;
+
+extern khm_handle afs_sub;
+
+/* defined in afsconfig.c which is generated from afsconfig.csv */
+extern kconf_schema schema_afsconfig[];
+
+
+/* plugin callback procedure */
+khm_int32 KHMAPI 
+afs_plugin_cb(khm_int32 msg_type,
+              khm_int32 msg_subtype,
+              khm_ui_4 uparam,
+              void * vparam);
+
+INT_PTR CALLBACK
+afs_cfg_ids_proc(HWND hwnd,
+                 UINT uMsg,
+                 WPARAM wParam,
+                 LPARAM lParam);
+
+INT_PTR CALLBACK
+afs_cfg_id_proc(HWND hwnd,
+                UINT uMsg,
+                WPARAM wParam,
+                LPARAM lParam);
+
+INT_PTR CALLBACK
+afs_cfg_main_proc(HWND hwnd,
+                  UINT uMsg,
+                  WPARAM wParam,
+                  LPARAM lParam);
+
+HWND
+afs_html_help(HWND caller,
+              wchar_t * postfix,
+              UINT cmd,
+              DWORD_PTR data);
+
+/* extensions */
+typedef afs_msg_announce afs_extension;
+
+/* not thread safe. only call from the plugin thread */
+afs_extension *
+afs_find_extension(const wchar_t * name);
+
+/* not thread safe. only call from the plugin thread */
+afs_extension *
+afs_get_extension(khm_size i);
+
+/* not thread safe.  only call from the plugin thread */
+afs_extension *
+afs_get_next_token_acq(afs_extension * f);
+
+/* not thread safe.  only call from the plugin thread */
+khm_boolean
+afs_is_valid_method_id(afs_tk_method method);
+
+afs_tk_method
+afs_get_next_method_id(afs_tk_method method);
+
+afs_tk_method
+afs_get_method_id(wchar_t * name);
+
+khm_boolean
+afs_get_method_name(afs_tk_method method, wchar_t * buf, khm_size cbbuf);
+
+afs_extension *
+afs_get_method_ext(afs_tk_method method);
+
+khm_boolean
+afs_method_describe(afs_tk_method method, khm_int32 flags,
+                    wchar_t * wbuf, khm_size cbbuf);
+
+khm_boolean
+afs_ext_resolve_token(const wchar_t * cell,
+                      const struct ktc_token * token,
+                      const struct ktc_principal * serverp,
+                      const struct ktc_principal * clientp,
+                      khm_handle * pident,
+                      afs_tk_method * pmethod);
+
+khm_boolean
+afs_ext_klog(afs_tk_method method,
+             khm_handle   identity,
+             const char * service,
+             const char * cell,
+             const char * realm,
+             const afs_conf_cell * cell_config,
+             khm_int32    lifetime);
+
+BOOL
+afs_cfg_get_afscreds_shortcut(wchar_t * wpath);
+
+#endif
diff --git a/src/WINNT/netidmgr_plugin/afsext.c b/src/WINNT/netidmgr_plugin/afsext.c
new file mode 100644 (file)
index 0000000..5a3e5d3
--- /dev/null
@@ -0,0 +1,454 @@
+/*
+ * Copyright (c) 2004 Massachusetts Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* $Id$ */
+
+#include<afscred.h>
+#include<assert.h>
+#include<wchar.h>
+
+/* supported API versions */
+#define AFS_PLUGIN_VERSION_MIN 0x00000001
+#define AFS_PLUGIN_VERSION_MAX AFS_PLUGIN_VERSION
+
+#define MAX_EXTENSIONS 8
+
+afs_extension extensions[MAX_EXTENSIONS];
+khm_size n_extensions = 0;
+khm_int32 next_method_id = AFS_TOKEN_USER;
+
+/* not threadsafe.  should only be called from the plugin thread */
+khm_int32
+afs_add_extension(afs_msg_announce * ann) {
+    size_t cbname = 0;
+    size_t cbtashort = 0;
+    size_t cbtalong = 0;
+    afs_extension * ext;
+    wchar_t * tmp;
+
+    if (ann->cbsize != sizeof(afs_msg_announce) ||
+        FAILED(StringCbLength(ann->name, KHUI_MAXCB_NAME, &cbname)) ||
+        ann->sub == NULL ||
+        (ann->provide_token_acq &&
+         ((FAILED(StringCbLength(ann->token_acq.short_desc,
+                                 KHUI_MAXCB_SHORT_DESC,
+                                 &cbtashort))) ||
+          (ann->token_acq.long_desc &&
+           FAILED(StringCbLength(ann->token_acq.long_desc,
+                                 KHUI_MAXCB_LONG_DESC,
+                                 &cbtalong))))) ||
+        ann->version < AFS_PLUGIN_VERSION_MIN ||
+        ann->version > AFS_PLUGIN_VERSION_MAX)
+
+        return KHM_ERROR_INVALID_PARAM;
+
+    if (n_extensions == MAX_EXTENSIONS)
+        return KHM_ERROR_NO_RESOURCES;
+
+    cbname += sizeof(wchar_t);
+    cbtashort += sizeof(wchar_t);
+    cbtalong += sizeof(wchar_t);
+
+    ext = &extensions[n_extensions];
+
+    *ext = *ann;
+
+    tmp = PMALLOC(cbname);
+#ifdef DEBUG
+    assert(tmp);
+#endif
+    StringCbCopy(tmp, cbname, ann->name);
+    ext->name = tmp;
+
+    if (ann->provide_token_acq) {
+        tmp = PMALLOC(cbtashort);
+#ifdef DEBUG
+        assert(tmp);
+#endif
+        StringCbCopy(tmp, cbtashort, ann->token_acq.short_desc);
+        ext->token_acq.short_desc = tmp;
+
+        if (ann->token_acq.long_desc) {
+            tmp = PMALLOC(cbtalong);
+#ifdef DEBUG
+            assert(tmp);
+#endif
+            StringCbCopy(tmp, cbtalong,
+                         ann->token_acq.long_desc);
+            ext->token_acq.long_desc = tmp;
+        } else {
+            ext->token_acq.long_desc = NULL;
+        }
+
+        ann->token_acq.method_id = next_method_id++;
+        ext->token_acq.method_id = ann->token_acq.method_id;
+    } else {
+        ZeroMemory(&ext->token_acq, sizeof(ext->token_acq));
+    }
+
+    n_extensions++;
+
+    return KHM_ERROR_SUCCESS;
+}
+
+void
+afs_free_extension(khm_int32 idx) {
+    afs_extension * ext;
+
+#ifdef DEBUG
+    assert(idx >= 0 && idx < (khm_int32) n_extensions);
+#endif
+
+    ext = &extensions[idx];
+
+    if (ext->name)
+        PFREE((void *) ext->name);
+    if (ext->token_acq.short_desc)
+        PFREE((void *) ext->token_acq.short_desc);
+    if (ext->token_acq.long_desc)
+        PFREE((void *) ext->token_acq.long_desc);
+    if (ext->sub)
+        kmq_delete_subscription(ext->sub);
+
+    ZeroMemory(ext, sizeof(*ext));
+}
+
+/* not thread safe.  only call from plugin thread */
+void
+afs_remove_extension(khm_int32 idx) {
+    if (idx < 0 || idx > (khm_int32) n_extensions)
+        return;
+
+    afs_free_extension(idx);
+
+    if (idx == n_extensions-1) {
+        n_extensions--;
+    } else {
+        MoveMemory(&extensions[idx], &extensions[idx + 1],
+                   (n_extensions - (idx+1)) * sizeof(*extensions));
+    }
+}
+
+/* not thread safe. only call from the plugin thread */
+afs_extension *
+afs_find_extension(const wchar_t * name) {
+    khm_size i;
+
+    for (i=0; i < n_extensions; i++) {
+        if (extensions[i].name &&
+            !wcscmp(extensions[i].name, name))
+            return &extensions[i];
+    }
+
+    return NULL;
+}
+
+/* not thread safe.  only call from the plugin thread */
+khm_boolean
+afs_is_valid_method_id(afs_tk_method method) {
+    khm_size i;
+
+    if (method == AFS_TOKEN_AUTO ||
+        method == AFS_TOKEN_KRB5 ||
+        method == AFS_TOKEN_KRB524 ||
+        method == AFS_TOKEN_KRB4)
+        return TRUE;
+
+    for (i=0; i < n_extensions; i++) {
+        if (extensions[i].provide_token_acq &&
+            extensions[i].token_acq.method_id == method)
+            return TRUE;
+    }
+
+    return FALSE;
+}
+
+khm_boolean
+afs_method_describe(afs_tk_method method, khm_int32 flags,
+                    wchar_t * wbuf, khm_size cbbuf) {
+    khm_size idx;
+
+    switch(method) {
+    case AFS_TOKEN_AUTO:
+        return LoadString(hResModule,
+                          ((flags & KCDB_TS_SHORT)? 
+                           IDS_NC_METHOD_AUTO:
+                           IDS_NC_METHODL_AUTO),
+                          wbuf, (int) cbbuf / sizeof(wchar_t));
+
+    case AFS_TOKEN_KRB5:
+        return LoadString(hResModule,
+                          ((flags & KCDB_TS_SHORT)?
+                           IDS_NC_METHOD_KRB5:
+                           IDS_NC_METHODL_KRB5),
+                          wbuf, (int) cbbuf / sizeof(wchar_t));
+
+    case AFS_TOKEN_KRB524:
+        return LoadString(hResModule,
+                          ((flags & KCDB_TS_SHORT)?
+                           IDS_NC_METHOD_KRB524:
+                           IDS_NC_METHODL_KRB524),
+                          wbuf, (int) cbbuf / sizeof(wchar_t));
+
+    case AFS_TOKEN_KRB4:
+        return LoadString(hResModule,
+                          ((flags & KCDB_TS_SHORT)?
+                           IDS_NC_METHOD_KRB4:
+                           IDS_NC_METHODL_KRB4),
+                          wbuf, (int) cbbuf / sizeof(wchar_t));
+
+    default:
+        for (idx = 0; idx < n_extensions; idx++) {
+            if(!extensions[idx].provide_token_acq ||
+               extensions[idx].token_acq.method_id != method)
+                continue;
+
+            if ((flags & KCDB_TS_SHORT) ||
+                extensions[idx].token_acq.long_desc == NULL)
+                return SUCCEEDED(StringCbCopy(wbuf, cbbuf,
+                                              extensions[idx].token_acq.short_desc));
+            else
+                return SUCCEEDED(StringCbCopy(wbuf, cbbuf,
+                                              extensions[idx].token_acq.long_desc));
+        }
+    }
+
+    return FALSE;
+}
+
+afs_tk_method
+afs_get_next_method_id(afs_tk_method method) {
+    khm_size idx;
+
+    switch(method) {
+    case -1:
+        return AFS_TOKEN_AUTO;
+    case AFS_TOKEN_AUTO:
+        return AFS_TOKEN_KRB5;
+    case AFS_TOKEN_KRB5:
+        return AFS_TOKEN_KRB524;
+    case AFS_TOKEN_KRB524:
+        return AFS_TOKEN_KRB4;
+    case AFS_TOKEN_KRB4:
+        idx = 0;
+        break;
+    default:
+        for(idx = 0; idx < n_extensions; idx ++) {
+            if (extensions[idx].provide_token_acq &&
+                extensions[idx].token_acq.method_id == method)
+                break;
+        }
+        idx++;
+    }
+
+    for(; idx < n_extensions; idx++) {
+        if (extensions[idx].provide_token_acq)
+            return extensions[idx].token_acq.method_id;
+    }
+
+    return -1;
+}
+
+/* not thread safe.  only call from the plugin thread */
+afs_extension *
+afs_get_next_token_acq(afs_extension * f) {
+    khm_size idx;
+
+    if (f == NULL)
+        idx = 0;
+    else
+        idx = (f - extensions) + 1;
+
+    for(; idx < n_extensions; idx++) {
+        if (extensions[idx].provide_token_acq)
+            return &extensions[idx];
+    }
+
+    return NULL;
+}
+
+afs_extension *
+afs_get_extension(khm_size i) {
+    if (i >= n_extensions)
+        return NULL;
+    else
+        return &extensions[i];
+}
+
+afs_tk_method
+afs_get_method_id(wchar_t * name) {
+    if (!wcscmp(name, AFS_TOKENNAME_AUTO))
+        return AFS_TOKEN_AUTO;
+    else if (!wcscmp(name, AFS_TOKENNAME_KRB5))
+        return AFS_TOKEN_KRB5;
+    else if (!wcscmp(name, AFS_TOKENNAME_KRB524))
+        return AFS_TOKEN_KRB524;
+    else if (!wcscmp(name, AFS_TOKENNAME_KRB4))
+        return AFS_TOKEN_KRB4;
+    else {
+        khm_size i;
+
+        for (i=0; i < n_extensions; i++) {
+            if (!extensions[i].provide_token_acq)
+                continue;
+
+            if (!wcscmp(extensions[i].name, name))
+                return extensions[i].token_acq.method_id;
+        }
+    }
+
+    return AFS_TOKEN_AUTO;
+}
+
+khm_boolean
+afs_get_method_name(afs_tk_method method, wchar_t * buf, khm_size cbbuf) {
+    if (method == AFS_TOKEN_AUTO)
+        return SUCCEEDED(StringCbCopy(buf, cbbuf, AFS_TOKENNAME_AUTO));
+    else if (method == AFS_TOKEN_KRB5)
+        return SUCCEEDED(StringCbCopy(buf, cbbuf, AFS_TOKENNAME_KRB5));
+    else if (method == AFS_TOKEN_KRB524)
+        return SUCCEEDED(StringCbCopy(buf, cbbuf, AFS_TOKENNAME_KRB524));
+    else if (method == AFS_TOKEN_KRB4)
+        return SUCCEEDED(StringCbCopy(buf, cbbuf, AFS_TOKENNAME_KRB4));
+    else {
+        khm_size i;
+
+        for (i=0; i < n_extensions; i++) {
+            if (!extensions[i].provide_token_acq)
+                continue;
+            if (extensions[i].token_acq.method_id == method)
+                return SUCCEEDED(StringCbCopy(buf, cbbuf,
+                                              extensions[i].name));
+        }
+    }
+
+    return FALSE;
+}
+
+/* not thread safe.  only call from the plugin thread */
+khm_boolean
+afs_ext_resolve_token(const wchar_t * cell,
+                      const struct ktc_token * token,
+                      const struct ktc_principal * serverp,
+                      const struct ktc_principal * clientp,
+                      khm_handle * pident,
+                      afs_tk_method * pmethod) {
+
+    afs_msg_resolve_token rt;
+    khm_size idx;
+    khm_int32 rv;
+
+    ZeroMemory(&rt, sizeof(rt));
+
+    rt.cbsize = sizeof(rt);
+
+    rt.cell = cell;
+    rt.token = token;
+    rt.serverp = serverp;
+    rt.clientp = clientp;
+    rt.method = AFS_TOKEN_AUTO;
+    rt.ident = NULL;
+
+    for (idx = 0; idx < n_extensions; idx++) {
+        if (!extensions[idx].provide_token_acq)
+            continue;
+
+        rv = kmq_send_sub_msg(extensions[idx].sub,
+                              afs_msg_type_id,
+                              AFS_MSG_RESOLVE_TOKEN,
+                              0,
+                              (void *) &rt);
+
+        if (KHM_SUCCEEDED(rv)) {
+            assert(rt.ident != NULL);
+
+            *pident = rt.ident;
+            *pmethod = rt.method;
+
+            return TRUE;
+        }
+    }
+
+    return FALSE;
+}
+
+/* not thread safe. only call from the plugin thread */
+khm_boolean
+afs_ext_klog(afs_tk_method method,
+             khm_handle   identity,
+             const char * service,
+             const char * cell,
+             const char * realm,
+             const afs_conf_cell * cell_config,
+             khm_int32    lifetime) {
+
+    khm_size idx;
+    khm_int32 rv = KHM_ERROR_GENERAL;
+    afs_msg_klog msg;
+    afs_conf_cell cellconfig;
+
+    ZeroMemory(&msg, sizeof(msg));
+    ZeroMemory(&cellconfig, sizeof(cellconfig));
+
+    msg.cbsize = sizeof(msg);
+
+    msg.identity = identity;
+    msg.service = service;
+    msg.cell = cell;
+    msg.realm = realm;
+    msg.lifetime = lifetime;
+
+    msg.cell_config = &cellconfig;
+
+    cellconfig = *cell_config;
+    cellconfig.cbsize = sizeof(cellconfig);
+
+    for (idx = 0; idx < n_extensions; idx++) {
+        if (!extensions[idx].provide_token_acq ||
+            (method != AFS_TOKEN_AUTO &&
+             extensions[idx].token_acq.method_id != method))
+            continue;
+
+        rv = kmq_send_sub_msg(extensions[idx].sub,
+                              afs_msg_type_id,
+                              AFS_MSG_KLOG,
+                              0,
+                              (void *) &msg);
+
+        if (KHM_SUCCEEDED(rv))
+            return TRUE;
+    }
+
+    return FALSE;
+}
+
+khm_int32 KHMAPI 
+afs_msg_ext(khm_int32 msg_subtype, khm_ui_4 uparam, void * vparam) {
+    switch(msg_subtype) {
+    case AFS_MSG_ANNOUNCE:
+        return afs_add_extension((afs_msg_announce *) vparam);
+    }
+
+    return KHM_ERROR_SUCCESS;
+}
diff --git a/src/WINNT/netidmgr_plugin/afsfuncs.c b/src/WINNT/netidmgr_plugin/afsfuncs.c
new file mode 100644 (file)
index 0000000..f27f323
--- /dev/null
@@ -0,0 +1,1432 @@
+/*
+ * Copyright (c) 2004 Massachusetts Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* $Id$ */
+
+/* Disable the 'macro redefinition' warning which is getting
+   triggerred by a redefinition of the ENCRYPT and DECRYPT macros. */
+#pragma warning (push)
+#pragma warning (disable: 4005)
+
+#include<afscred.h>
+#include<dynimport.h>
+#include<krb5common.h>
+
+#pragma warning (pop)
+
+BOOL
+afs_is_running(void) {
+    DWORD CurrentState;
+
+    if (!AfsAvailable)
+        return FALSE;
+
+    if (GetServiceStatus(NULL, TRANSARCAFSDAEMON, 
+                         &CurrentState, NULL) != NOERROR)
+        return FALSE;
+    if (CurrentState != SERVICE_RUNNING)
+        return FALSE;
+
+    return TRUE;
+}
+
+int
+afs_unlog(void)
+{
+    long       rc;
+
+    if (!afs_is_running())
+        return 0;
+
+    rc = ktc_ForgetAllTokens();
+
+    return rc;
+}
+
+int
+afs_unlog_cred(khm_handle cred)
+{
+    long rc;
+    struct ktc_principal princ;
+    khm_size cbbuf;
+    wchar_t name[KCDB_MAXCCH_NAME];
+
+    if (!afs_is_running())
+        return 0;
+
+    cbbuf = sizeof(princ);
+    if(KHM_FAILED(kcdb_cred_get_attr(cred, afs_attr_server_princ, 
+                                     NULL, &princ, &cbbuf)))
+        return 1;
+
+    afs_princ_to_string(&princ, name, sizeof(name));
+
+    _report_cs1(KHERR_INFO, L"Destroying token %1!s!",
+                _cstr(name));
+    _resolve();
+
+    rc = ktc_ForgetToken(&princ);
+
+    return rc;
+}
+
+/* convert a ktc_principal to a wchar_t string form that looks like
+    name.instance@cell return 0 if it worked. non-zero otherwise
+*/
+int 
+afs_princ_to_string(struct ktc_principal * p, 
+                    wchar_t * buf, 
+                    size_t cbbuf)
+{
+    wchar_t wbuf[256];
+    int rv = 0;
+    int l;
+
+    l = AnsiStrToUnicode(wbuf, sizeof(wbuf), p->name);
+    wbuf[l] = L'\0';
+
+    rv = FAILED(StringCbCopy(buf, cbbuf, wbuf));
+    if(p->instance[0]) {
+        StringCbCat(buf, cbbuf, L".");
+        if((l = AnsiStrToUnicode(wbuf, sizeof(wbuf), p->instance)) > 0) {
+            wbuf[l] = L'\0';
+            rv = rv || FAILED(StringCbCat(buf, cbbuf, wbuf));
+        }
+        else
+            rv = 1;
+    }
+    if(p->cell[0]) {
+        rv = rv || FAILED(StringCbCat(buf, cbbuf, L"@"));
+        if((l = AnsiStrToUnicode(wbuf, sizeof(wbuf), p->cell)) > 0) {
+            wbuf[l] = L'\0';
+            rv = rv || FAILED(StringCbCat(buf, cbbuf, wbuf));
+        }
+        else
+            rv = 1;
+    }
+
+    return rv;
+}
+
+int 
+afs_list_tokens(void)
+{
+    int r;
+
+    kcdb_credset_flush(afs_credset);
+    r = afs_list_tokens_internal();
+    kcdb_credset_collect(NULL, afs_credset, NULL, afs_credtype_id, NULL);
+
+    return r;
+}
+
+/* is the credential provided an AFS token and is it from the
+   specified cell? */
+static khm_int32 KHMAPI 
+afs_filter_by_cell(khm_handle cred, khm_int32 flags, void * rock)
+{
+    wchar_t wcell[MAXCELLCHARS];
+    wchar_t * tcell;
+    khm_size cbsize;
+    khm_int32 type;
+
+    tcell = (wchar_t *) rock;
+
+    if(KHM_FAILED(kcdb_cred_get_type(cred, &type)) ||
+        type != afs_credtype_id)
+        return FALSE;
+
+    cbsize = sizeof(wcell);
+    if(KHM_FAILED(kcdb_cred_get_attr(cred, afs_attr_cell, 
+                                     NULL, wcell, &cbsize)))
+        return FALSE;
+
+    if(wcscmp(wcell, tcell))
+        return FALSE;
+
+    return TRUE;
+}
+
+struct token_filter_data {
+    wchar_t * cell;
+};
+
+khm_int32 KHMAPI
+afs_filter_for_token(khm_handle cred, khm_int32 flags, void * rock) {
+    struct token_filter_data * pdata;
+    wchar_t ccell[MAXCELLCHARS];
+    khm_size cb;
+    khm_int32 ctype;
+
+    pdata = (struct token_filter_data *) rock;
+
+    if (KHM_FAILED(kcdb_cred_get_type(cred, &ctype)) ||
+        ctype != afs_credtype_id)
+
+        return 0;
+
+    cb = sizeof(ccell);
+
+    if (KHM_FAILED(kcdb_cred_get_attr(cred, afs_attr_cell,
+                                      NULL,
+                                      ccell,
+                                      &cb)) ||
+        _wcsicmp(ccell, pdata->cell))
+
+        return 0;
+
+    return 1;
+}
+
+khm_handle
+afs_find_token(khm_handle credset, wchar_t * cell) {
+    struct token_filter_data fdata;
+    khm_handle cred = NULL;
+
+    fdata.cell = cell;
+
+    if (KHM_FAILED(kcdb_credset_find_filtered(credset,
+                                              -1,
+                                              afs_filter_for_token,
+                                              &fdata,
+                                              &cred,
+                                              NULL)))
+        return NULL;
+    else
+        return cred;
+}
+
+static khm_int32 KHMAPI 
+afs_filter_krb5_tkt(khm_handle cred, khm_int32 flags, void * rock) 
+{
+    wchar_t cname[KCDB_CRED_MAXCCH_NAME];
+    khm_int32 type;
+    wchar_t * tcell;
+    wchar_t * t, *tkt_cell;
+    khm_size cbsize;
+
+    tcell = (wchar_t *) rock;
+
+    if(KHM_FAILED(kcdb_cred_get_type(cred, &type)) ||
+       type != krb5_credtype_id)
+        return FALSE;
+
+    cbsize = sizeof(cname);
+    if (KHM_FAILED(kcdb_cred_get_name(cred, cname, &cbsize)))
+        return FALSE;
+
+    if (!wcsncmp(cname, L"afs/", 4)) {
+
+        tkt_cell = cname + 4;
+
+        t = wcschr(tkt_cell, L'@');
+        if (t == NULL)
+            return FALSE;
+        *t = L'\0';
+
+    } else if (!wcsncmp(cname, L"afs@", 4)) {
+
+        tkt_cell = cname + 4;
+
+    } else {
+        return FALSE;
+    }
+
+    if (_wcsicmp(tcell, tkt_cell))
+        return FALSE;
+
+    return TRUE;
+}
+
+static khm_int32 KHMAPI 
+afs_filter_krb4_tkt(khm_handle cred, khm_int32 flags, void * rock) 
+{
+    wchar_t cname[KCDB_CRED_MAXCCH_NAME];
+    khm_int32 type;
+    wchar_t * tcell;
+    wchar_t * t, *tkt_cell;
+    khm_size cbsize;
+
+    tcell = (wchar_t *) rock;
+
+    if(KHM_FAILED(kcdb_cred_get_type(cred, &type)) ||
+       type != krb4_credtype_id)
+        return FALSE;
+
+    cbsize = sizeof(cname);
+    if (KHM_FAILED(kcdb_cred_get_name(cred, cname, &cbsize)))
+        return FALSE;
+
+    if (!wcsncmp(cname, L"afs.", 4)) {
+
+        tkt_cell = cname + 4;
+
+        t = wcschr(tkt_cell, L'@');
+        if (t == NULL)
+            return FALSE;
+        *t = L'\0';
+
+    } else if (!wcsncmp(cname, L"afs@", 4)) {
+
+        tkt_cell = cname + 4;
+
+    } else {
+        return FALSE;
+    }
+
+    if (_wcsicmp(tcell, tkt_cell))
+        return FALSE;
+
+    return TRUE;
+}
+
+/* collects all AFS tokens to the root credential set using the
+   generic afs_credset credential set
+   */
+int
+afs_list_tokens_internal(void)
+{
+    struct ktc_principal    aserver;
+    struct ktc_principal    aclient;
+    struct ktc_token        atoken;
+    int                     cellNum;
+    int                     BreakAtEnd;
+    wchar_t                 idname[256];
+    wchar_t                 crname[256];
+    wchar_t                 location[256];
+    wchar_t                 *cell;
+
+    DWORD                   rc;
+
+    khm_handle              ident = NULL;
+    khm_handle              cred = NULL;
+    afs_tk_method           method;
+
+    FILETIME                ft;
+
+    if (!afs_is_running())
+        return 0;
+
+    kcdb_credset_flush(afs_credset);
+
+    LoadString(hResModule, IDS_DEF_LOCATION, location, ARRAYLENGTH(location));
+
+    BreakAtEnd = 0;
+    cellNum = 0;
+    while (1) 
+    {
+        memset(&aserver, 0, sizeof(aserver));
+        if (rc = ktc_ListTokens(cellNum, &cellNum, &aserver))
+        {
+            if (rc != KTC_NOENT)
+                return(0);
+
+            if (BreakAtEnd == 1)
+                break;
+        }
+        BreakAtEnd = 1;
+        memset(&atoken, '\0', sizeof(atoken));
+        if (rc = ktc_GetToken(&aserver, &atoken, sizeof(atoken), &aclient))
+        {
+            if (rc == KTC_ERROR)
+                return(0);
+
+            continue;
+        }
+
+#if 0
+        /* failed attempt at trying to figure out the principal name from
+           the token.  The ticket that is attached to the token is not
+           in a form that is useful at this point */
+        idname[0] = L'\0';
+        if(atoken.kvno == RXKAD_TKT_TYPE_KERBEROS_V5) {
+            krb5_context ctx = 0;
+            krb5_ccache cc = 0;
+            krb5_creds * k5c;
+            krb5_error_code code;
+            char * princ;
+
+            code = khm_krb5_initialize(&ctx, &cc);
+            if(code)
+                goto _no_krb5;
+
+            k5c = (krb5_creds *) atoken.ticket;
+
+            code = pkrb5_unparse_name(ctx, k5c->client, &princ);
+            if(code)
+                goto _no_krb5;
+
+            MultiByteToWideChar(CP_ACP, 0, princ, strlen(princ), idname, sizeof(idname)/sizeof(idname[0]));
+
+            pkrb5_free_unparsed_name(ctx, princ);
+_no_krb5:
+            ;
+        }
+#endif
+
+        method = AFS_TOKEN_AUTO;
+
+        afs_princ_to_string(&aclient, idname, sizeof(idname));
+
+        /* We need to figure out a good client name which we can use
+           to create an identity which looks familiar to the user.  No
+           good way of doing this, so we use a heuristic.
+
+           Note that, we use another heuristic to find out which
+           identity to associate the token with.
+   
+           ASSUMPTION:
+
+           The assumption here is that the principal for the token is
+           computed as follows:
+           
+           if realm != cell : principal looks like user@realm@cell
+           if realm == cell : principal looks like user@realm
+        
+           HEURISTIC:
+        
+           We strip the part of the string that follows the second '@'
+           sign to obtain the 'user@realm' part, which we use as the
+           credential name.  If there is no second '@', we use the
+           whole principal name. */
+        {
+            wchar_t * ats;
+
+            ats = wcschr(idname, L'@');
+            if(ats && (ats = wcschr(ats + 1, L'@')))
+                *ats = L'\0';
+        }
+
+        afs_princ_to_string(&aserver, crname, sizeof(crname));
+
+        /* Ok, now we need to figure out which identity to associate
+           this token with.  This is a little bit tricky, and there is
+           currently no good way of determining the original identity
+           used to obtain the token if it was done outside of
+           NetIDMgr.  So we use a heuristic here.
+
+           REQUIREMENT:
+
+           Elsewhere, (actually in afsnewcreds.c) just after obtaining
+           AFS tokens through NetIDMgr, we enumerate the AFS tokens
+           and assign the root identity (used to obtain new creds)
+           with the AFS tokens.  This would still be there in the root
+           credential set when we list tokens later on.
+
+           HEURISTIC:
+
+           If there exists an AFS token in the root credential set for
+           the same cell, we associate this token with the same
+           identity as that credential.
+        */
+        cell = wcschr(crname, L'@');
+        if(cell) {
+            cell++;
+            if(!*cell)
+                cell = NULL;
+        }
+
+        ident = NULL;
+        if(cell) {
+            khm_handle c;
+
+            if(KHM_SUCCEEDED(kcdb_credset_find_filtered(NULL, -1, 
+                                                        afs_filter_by_cell, 
+                                                        (void *) cell, 
+                                                        &c, NULL))) {
+                khm_size cb;
+
+                kcdb_cred_get_identity(c, &ident);
+                cb = sizeof(method);
+                kcdb_cred_get_attr(c, afs_attr_method, NULL,
+                                   &method, &cb);
+                kcdb_cred_release(c);
+            }
+        }
+
+        /* If that failed, we have try another trick.  If there is a
+           Krb5 ticket of the form afs/<cell>@<realm> or afs@<CELL>
+           where <cell> matches our cell, then we pick the identity
+           off of that.
+
+           ASSUMPTION:
+
+           If Krb5 was used to obatain the token, then there is a Krb5
+           ticket of the form afs/<cell>@<REALM> or afs@<CELL> still
+           in the cache.  This is also true for Krb524 token
+           acquisition.
+
+           HEURISTIC:
+
+           If such a Krb5 ticket is found, use the identity of that
+           credential as the identity of the AFS token.
+
+        */
+        if (ident == NULL && cell != NULL) {
+            khm_handle c;
+
+            if(KHM_SUCCEEDED(kcdb_credset_find_filtered(NULL, -1, 
+                                                        afs_filter_krb5_tkt,
+                                                        (void *) cell, 
+                                                        &c, NULL))) {
+                kcdb_cred_get_identity(c, &ident);
+                /* this could be Krb5 or Krb524, so we leave method at
+                   AFS_TOKEN_AUTO. */
+                method = AFS_TOKEN_AUTO;
+                kcdb_cred_release(c);
+            }
+        }
+
+        /* If that didn't work either, we look for a Krb4 ticket of
+           the form afs.<cell>@<REALM> or afs@<CELL> which matches the
+           cell. 
+
+           ASSUMPTION:
+
+           If Krb4 was used to obtain an AFS token, then there should
+           be a Krb4 ticket of the form afs.<cell>@<REALM> or
+           afs@<CELL> in the cache.
+
+           HEURISTIC:
+
+           If such a ticket is found, then use the identity of that
+           credential as the identity of the AFS token.
+        */
+        if (ident == NULL && cell != NULL) {
+            khm_handle c;
+
+            if (krb4_credtype_id < 0) {
+                kcdb_credtype_get_id(KRB4_CREDTYPE_NAME,
+                                     &krb4_credtype_id);
+            }
+
+            if (krb4_credtype_id > 0 &&
+                KHM_SUCCEEDED(kcdb_credset_find_filtered(NULL, -1,
+                                                         afs_filter_krb4_tkt,
+                                                         (void *) cell,
+                                                         &c, NULL))) {
+
+                kcdb_cred_get_identity(c, &ident);
+                kcdb_cred_release(c);
+                method = AFS_TOKEN_KRB4;
+
+            }
+        }
+
+        /* Finally, we allow any extension plugins to give this a shot */
+        if (ident == NULL && cell != NULL) {
+            afs_ext_resolve_token(cell,
+                                  &atoken,
+                                  &aserver,
+                                  &aclient,
+                                  &ident,
+                                  &method);
+        }
+
+        /* One more thing to try.  If we have a cell->identity
+           mapping, then we try that. */
+        if (ident == NULL && cell != NULL) {
+            khm_handle h_cellmap;
+            wchar_t tidname[KCDB_IDENT_MAXCCH_NAME];
+            khm_size cb;
+
+            cb = sizeof(tidname);
+
+            if (KHM_SUCCEEDED(khc_open_space(csp_afscred,
+                                             L"Cells", 0, 
+                                             &h_cellmap))) {
+                if (KHM_SUCCEEDED(khc_read_string(h_cellmap,
+                                                  cell,
+                                                  tidname,
+                                                  &cb))) {
+                    kcdb_identity_create(tidname,
+                                         KCDB_IDENT_FLAG_CREATE,
+                                         &ident);
+                }
+                khc_close_space(h_cellmap);
+            }
+        }
+
+        /* all else failed */
+        if(ident == NULL) {
+            if(KHM_FAILED(kcdb_identity_create(idname, 
+                                               KCDB_IDENT_FLAG_CREATE, 
+                                               &ident)))
+                goto _exit;
+        }
+
+        if(KHM_FAILED(kcdb_cred_create(crname, ident, afs_credtype_id, &cred)))
+            goto _exit;
+
+        kcdb_cred_set_attr(cred, afs_attr_method, &method, sizeof(method));
+
+        TimetToFileTime(atoken.endTime, &ft);
+        kcdb_cred_set_attr(cred, KCDB_ATTR_EXPIRE, &ft, sizeof(ft));
+        if (atoken.startTime != 0) {
+            TimetToFileTime(atoken.startTime, &ft);
+            kcdb_cred_set_attr(cred, KCDB_ATTR_ISSUE, &ft, sizeof(ft));
+        }
+        kcdb_cred_set_attr(cred, afs_attr_client_princ, 
+                           &aclient, sizeof(aclient));
+        kcdb_cred_set_attr(cred, afs_attr_server_princ, 
+                           &aserver, sizeof(aserver));
+
+        if(cell) {
+            kcdb_cred_set_attr(cred, afs_attr_cell, cell, KCDB_CBSIZE_AUTO);
+        }
+
+        kcdb_cred_set_attr(cred, KCDB_ATTR_LOCATION, 
+                           location, KCDB_CBSIZE_AUTO);
+
+        kcdb_credset_add_cred(afs_credset, cred, -1);
+
+        /* both these calls are NULL pointer safe */
+        kcdb_cred_release(cred);
+        cred = NULL;
+        kcdb_identity_release(ident);
+        ident = NULL;
+    }
+
+_exit:
+    if(ident)
+        kcdb_identity_release(ident);
+    if(cred)
+        kcdb_cred_release(cred);
+
+    return(0);
+}
+
+
+#define ALLOW_REGISTER 1
+static int
+ViceIDToUsername(char *username, 
+                 char *realm_of_user, 
+                 char *realm_of_cell,
+                 char * cell_to_use,
+                 struct ktc_principal *aclient, 
+                 struct ktc_principal *aserver, 
+                 struct ktc_token *atoken)
+{
+    static char lastcell[MAXCELLCHARS+1] = { 0 };
+    static char confname[512] = { 0 };
+#ifdef AFS_ID_TO_NAME
+    char username_copy[BUFSIZ];
+#endif /* AFS_ID_TO_NAME */
+    long viceId = ANONYMOUSID;         /* AFS uid of user */
+    int  status = 0;
+#ifdef ALLOW_REGISTER
+    afs_int32 id;
+#endif /* ALLOW_REGISTER */
+
+    if (confname[0] == '\0') {
+        StringCbCopyA(confname, sizeof(confname), AFSDIR_CLIENT_ETC_DIRPATH);
+    }
+
+    StringCbCopyA(lastcell, sizeof(lastcell), aserver->cell);
+
+    if (!pr_Initialize (0, confname, aserver->cell)) {
+        char sname[PR_MAXNAMELEN];
+        StringCbCopyA(sname, sizeof(sname), username);
+        status = pr_SNameToId (sname, &viceId);
+       pr_End();
+    }
+
+    /*
+     * This is a crock, but it is Transarc's crock, so
+     * we have to play along in order to get the
+     * functionality.  The way the afs id is stored is
+     * as a string in the username field of the token.
+     * Contrary to what you may think by looking at
+     * the code for tokens, this hack (AFS ID %d) will
+     * not work if you change %d to something else.
+     */
+
+    /*
+     * This code is taken from cklog -- it lets people
+     * automatically register with the ptserver in foreign cells
+     */
+
+#ifdef ALLOW_REGISTER
+    if (status == 0) {
+        if (viceId != ANONYMOUSID) {
+#else /* ALLOW_REGISTER */
+           if ((status == 0) && (viceId != ANONYMOUSID))
+#endif /* ALLOW_REGISTER */
+    {
+#ifdef AFS_ID_TO_NAME
+       StringCbCopyA(username_copy, BUFSIZ, username);
+       StringCchPrintfA(username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId);
+#endif /* AFS_ID_TO_NAME */
+    }
+#ifdef ALLOW_REGISTER
+        } else if (strcmp(realm_of_user, realm_of_cell) != 0) {
+            id = 0;
+            StringCbCopyA(aclient->name, sizeof(aclient->name), username);
+            StringCbCopyA(aclient->instance, sizeof(aclient->instance), "");
+            StringCbCopyA(aclient->cell, sizeof(aclient->cell), realm_of_user);
+            if (status = ktc_SetToken(aserver, atoken, aclient, 0))
+                return status;
+            if (status = pr_Initialize(1L, confname, aserver->cell))
+                return status;
+            status = pr_CreateUser(username, &id);
+           pr_End();
+           if (status)
+               return status;
+#ifdef AFS_ID_TO_NAME
+            StringCbCopyA(username_copy, BUFSIZ, username);
+            StringCchPrintfA(username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId);
+#endif /* AFS_ID_TO_NAME */
+        }
+    }
+#endif /* ALLOW_REGISTER */
+    return status;
+}
+
+
+int
+afs_klog(khm_handle identity,
+         char *service,
+         char *cell,
+         char *realm,
+         int LifeTime,
+         afs_tk_method method,
+         time_t * tok_expiration) {
+
+    long       rc;
+    CREDENTIALS        creds;
+    struct ktc_principal       aserver;
+    struct ktc_principal       aclient;
+    char       realm_of_user[REALM_SZ]; /* Kerberos realm of user */
+    char       realm_of_cell[REALM_SZ]; /* Kerberos realm of cell */
+    char       local_cell[MAXCELLCHARS+1];
+    char       Dmycell[MAXCELLCHARS+1];
+    struct ktc_token   atoken;
+    struct ktc_token   btoken;
+    afs_conf_cell      ak_cellconfig; /* General information about the cell */
+    char       RealmName[128];
+    char       CellName[128];
+    char       ServiceName[128];
+       khm_handle      confighandle;
+       khm_int32       supports_krb4 = 1;
+
+    /* signalling */
+    BOOL        bGotCreds = FALSE; /* got creds? */
+
+    if (tok_expiration)
+        *tok_expiration = (time_t) 0;
+
+    if (!afs_is_running()) {
+        _report_sr0(KHERR_WARNING, IDS_ERR_NOSERVICE);
+        return(0);
+    }
+
+    if ( !realm )   realm = "";
+    if ( !cell )    cell = "";
+    if ( !service ) service = "";
+
+    memset(RealmName, '\0', sizeof(RealmName));
+    memset(CellName, '\0', sizeof(CellName));
+    memset(ServiceName, '\0', sizeof(ServiceName));
+    memset(realm_of_user, '\0', sizeof(realm_of_user));
+    memset(realm_of_cell, '\0', sizeof(realm_of_cell));
+    memset(Dmycell, '\0', sizeof(Dmycell));
+
+    // NULL or empty cell returns information on local cell
+    if (cell && cell[0])
+        StringCbCopyA(Dmycell, sizeof(Dmycell), cell);
+
+    rc = afs_get_cellconfig(Dmycell, &ak_cellconfig, local_cell);
+    if (rc) {
+        _reportf(L"afs_get_cellconfig returns %ld", rc);
+
+        _report_sr2(KHERR_ERROR, IDS_ERR_CELLCONFIG, _cstr(Dmycell), _int32(rc));
+        _suggest_sr(IDS_ERR_CELLCONFIG_S, KHERR_SUGGEST_NONE);
+        _resolve();
+        return(rc);
+    }
+
+    StringCbCopyA(realm_of_cell, sizeof(realm_of_cell), 
+                  afs_realm_of_cell(&ak_cellconfig));
+
+    if (strlen(service) == 0)
+        StringCbCopyA(ServiceName, sizeof(ServiceName), "afs");
+    else
+        StringCbCopyA(ServiceName, sizeof(ServiceName), service);
+
+    if (strlen(cell) == 0)
+        StringCbCopyA(CellName, sizeof(CellName), local_cell);
+    else
+        StringCbCopyA(CellName, sizeof(CellName), cell);
+
+    if (strlen(realm) == 0)
+        StringCbCopyA(RealmName, sizeof(RealmName), realm_of_cell);
+    else
+        StringCbCopyA(RealmName, sizeof(RealmName), realm);
+
+    memset(&creds, '\0', sizeof(creds));
+
+    /*** Kerberos 5 and 524 ***/
+
+    if (method == AFS_TOKEN_AUTO ||
+        method == AFS_TOKEN_KRB5 ||
+        method == AFS_TOKEN_KRB524) {
+
+        krb5_context   context = 0;
+        krb5_ccache    k5cc = 0;
+        krb5_creds     increds;
+        krb5_creds *   k5creds = 0;
+        krb5_error_code r;
+        krb5_principal client_principal = 0;
+        krb5_flags     flags = 0;
+
+        int         retry = 0;
+        int         len;
+       char        *p;
+
+        _reportf(L"Trying Kerberos 5");
+
+        if (!(r = khm_krb5_initialize(identity, &context, &k5cc))) {
+            int i;
+
+            memset((char *)&increds, 0, sizeof(increds));
+
+            (*pkrb5_cc_get_principal)(context, k5cc, &client_principal);
+            i = krb5_princ_realm(context, client_principal)->length;
+            if (i > REALM_SZ-1) 
+                i = REALM_SZ-1;
+            StringCchCopyNA(realm_of_user, ARRAYLENGTH(realm_of_user),
+                            krb5_princ_realm(context, client_principal)->data,
+                            i);
+        } else {
+            _reportf(L"khm_krb5_initialize returns code %d", r);
+            goto try_krb4;
+        }
+
+        /* First try Service/Cell@REALM */
+        if (r = (*pkrb5_build_principal)(context, &increds.server,
+                                         (int) strlen(RealmName),
+                                         RealmName,
+                                         ServiceName,
+                                         CellName,
+                                         0)) {
+            _reportf(L"krb5_build_principal returns %d", r);
+            goto end_krb5;
+        }
+
+        increds.client = client_principal;
+        increds.times.endtime = 0;
+        /* Ask for DES since that is what V4 understands */
+        increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC;
+
+#ifdef KRB5_TC_NOTICKET
+        flags = 0;
+        r = pkrb5_cc_set_flags(context, k5cc, flags);
+#endif
+        r = pkrb5_get_credentials(context, 0, k5cc, &increds, &k5creds);
+        if (r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
+            r == KRB5KRB_ERR_GENERIC /* Heimdal */) {
+            /* Next try Service@REALM */
+            pkrb5_free_principal(context, increds.server);
+            r = (*pkrb5_build_principal)(context, &increds.server,
+                                         (int) strlen(RealmName),
+                                         RealmName,
+                                         ServiceName,
+                                         0);
+            if (r == 0)
+                r = pkrb5_get_credentials(context, 0, k5cc, 
+                                          &increds, &k5creds);
+        }
+
+        pkrb5_free_principal(context, increds.server);
+        pkrb5_free_principal(context, client_principal);
+        client_principal = 0;
+#ifdef KRB5_TC_NOTICKET
+        flags = KRB5_TC_NOTICKET;
+        pkrb5_cc_set_flags(context, k5cc, flags);
+#endif
+
+        (void) pkrb5_cc_close(context, k5cc);
+        k5cc = 0;
+
+        if (r) {
+            _reportf(L"Code %d while getting credentials", r);
+            goto end_krb5;
+        }
+
+        if ( k5creds->ticket.length > MAXKTCTICKETLEN ||
+             method == AFS_TOKEN_KRB524) {
+            goto try_krb524d;
+        }
+
+        /* This code inserts the entire K5 ticket into the token */
+
+        _reportf(L"Trying K5 SetToken");
+
+        memset(&aserver, '\0', sizeof(aserver));
+        StringCchCopyA(aserver.name, MAXKTCNAMELEN, ServiceName);
+        StringCchCopyA(aserver.cell, MAXKTCREALMLEN, CellName);
+
+        memset(&atoken, '\0', sizeof(atoken));
+        atoken.kvno = RXKAD_TKT_TYPE_KERBEROS_V5;
+        atoken.startTime = k5creds->times.starttime;
+        atoken.endTime = k5creds->times.endtime;
+        memcpy(&atoken.sessionKey, 
+               k5creds->keyblock.contents, 
+               k5creds->keyblock.length);
+        atoken.ticketLen = k5creds->ticket.length;
+        memcpy(atoken.ticket, k5creds->ticket.data, atoken.ticketLen);
+
+        if (tok_expiration)
+            *tok_expiration = k5creds->times.endtime;
+
+    retry_gettoken5:
+        rc = ktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient);
+        if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) {
+            if ( rc == KTC_NOCM && retry < 20 ) {
+                Sleep(500);
+                retry++;
+                goto retry_gettoken5;
+            }
+            goto try_krb524d;
+        }
+
+        if (atoken.kvno == btoken.kvno &&
+            atoken.ticketLen == btoken.ticketLen &&
+            !memcmp(&atoken.sessionKey, &btoken.sessionKey, 
+                    sizeof(atoken.sessionKey)) &&
+            !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen)) {
+
+            /* success */
+            if (k5creds && context)
+                pkrb5_free_creds(context, k5creds);
+
+            if (context)
+                pkrb5_free_context(context);
+
+            _reportf(L"Same token already exists");
+            
+            return 0;
+        }
+
+        // * Reset the "aclient" structure before we call ktc_SetToken.
+        // * This structure was first set by the ktc_GetToken call when
+        // * we were comparing whether identical tokens already existed.
+
+        len = min(k5creds->client->data[0].length,MAXKTCNAMELEN - 1);
+        StringCchCopyNA(aclient.name, MAXKTCNAMELEN,
+                        k5creds->client->data[0].data, len);
+
+        if ( k5creds->client->length > 1 ) {
+            StringCbCatA(aclient.name, sizeof(aclient.name), ".");
+            p = aclient.name + strlen(aclient.name);
+            len = (int) min(k5creds->client->data[1].length,
+                            MAXKTCNAMELEN - strlen(aclient.name) - 1);
+            StringCchCopyNA(p, MAXKTCNAMELEN - strlen(aclient.name),
+                            k5creds->client->data[1].data, len);
+        }
+
+        aclient.instance[0] = '\0';
+
+        StringCbCopyA(aclient.cell, sizeof(aclient.cell), realm_of_cell);
+
+       StringCbCatA(aclient.name, sizeof(aclient.name), "@");
+       p = aclient.name + strlen(aclient.name);
+       len = (int) min(k5creds->client->realm.length,
+                        MAXKTCNAMELEN - strlen(aclient.name) - 1);
+        StringCchCopyNA(p, MAXKTCNAMELEN - strlen(aclient.name),
+                        k5creds->client->realm.data, len);
+
+        ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName, 
+                         &aclient, &aserver, &atoken);
+
+        rc = ktc_SetToken(&aserver, &atoken, &aclient, 0);
+        if (!rc) {
+            /* success */
+
+            if (k5creds && context)
+                pkrb5_free_creds(context, k5creds);
+
+            if (context)
+                pkrb5_free_context(context);
+            
+            return 0;
+        }
+
+        _reportf(L"SetToken returns code %d", rc);
+
+    try_krb524d:
+
+        _reportf(L"Trying Krb524");
+
+        if (method == AFS_TOKEN_AUTO ||
+            method == AFS_TOKEN_KRB524) {
+            /* This requires krb524d to be running with the KDC */
+            r = pkrb524_convert_creds_kdc(context, k5creds, &creds);
+            if (r) {
+                _reportf(L"Code %d while converting credentials", r);
+                goto end_krb5;
+            }
+            rc = KSUCCESS;
+            bGotCreds = TRUE;
+        }
+
+    end_krb5:
+        if (client_principal)
+            pkrb5_free_principal(context, client_principal);
+
+        if (k5creds && context)
+            pkrb5_free_creds(context, k5creds);
+
+        if (context)
+            pkrb5_free_context(context);
+    }
+
+    /* Kerberos 4 */
+ try_krb4:
+
+    kcdb_identity_get_config(identity, 0, &confighandle);
+    khc_read_int32(confighandle, L"Krb4Cred\\Krb4NewCreds", &supports_krb4);
+    khc_close_space(confighandle);
+
+    if (!supports_krb4) {
+        _reportf(L"Kerberos 4 not configured");
+    }
+
+    if (!bGotCreds && supports_krb4 && 
+        (method == AFS_TOKEN_AUTO ||
+         method == AFS_TOKEN_KRB4)) {
+
+        KTEXT_ST       ticket;
+
+        _reportf(L"Trying Kerberos 4");
+
+        if (!realm_of_user[0] ) {
+            if ((rc = (*pkrb_get_tf_realm)((*ptkt_string)(), realm_of_user)) 
+                != KSUCCESS) {
+                /* can't determine realm of user */
+                _reportf(L"krb_get_tf_realm returns %d", rc);
+                goto end_krb4;
+            }
+        }
+
+        _reportf(L"Trying to find %S.%S@%S", ServiceName, CellName, RealmName);
+        rc = (*pkrb_get_cred)(ServiceName, CellName, RealmName, &creds);
+        if (rc == NO_TKT_FIL) {
+            // if the problem is that we have no krb4 tickets
+            // do not attempt to continue
+            _reportf(L"krb_get_cred returns %d (no ticket file)", rc);
+            goto end_krb4;
+        }
+
+        if (rc != KSUCCESS) {
+            _reportf(L"Trying to find %S@%S", ServiceName, RealmName);
+            rc = (*pkrb_get_cred)(ServiceName, "", RealmName, &creds);
+        }
+
+        if (rc != KSUCCESS) {
+            _reportf(L"Trying to obtain new ticket");
+            if ((rc = (*pkrb_mk_req)(&ticket, ServiceName, 
+                                     CellName, RealmName, 0))
+                == KSUCCESS) {
+                if ((rc = (*pkrb_get_cred)(ServiceName, CellName, 
+                                           RealmName, &creds)) != KSUCCESS) {
+                    goto end_krb4;
+                } else {
+                    _reportf(L"Got %S.%S@%S", ServiceName, CellName, RealmName);
+                }
+            } else if ((rc = (*pkrb_mk_req)(&ticket, ServiceName, 
+                                            "", RealmName, 0))
+                       == KSUCCESS) {
+                if ((rc = (*pkrb_get_cred)(ServiceName, "", 
+                                           RealmName, &creds)) != KSUCCESS) {
+                    goto end_krb4;
+                } else {
+                    _reportf(L"Got %S@%S", ServiceName, RealmName);
+                }
+            } else {
+                goto end_krb4;
+            }
+        }
+
+        bGotCreds = TRUE;
+
+    end_krb4:
+        ;
+    }
+
+    if (bGotCreds) {
+
+        memset(&aserver, '\0', sizeof(aserver));
+        StringCchCopyA(aserver.name, MAXKTCNAMELEN, ServiceName);
+        StringCchCopyA(aserver.cell, MAXKTCREALMLEN, CellName);
+
+        memset(&atoken, '\0', sizeof(atoken));
+        atoken.kvno = creds.kvno;
+        atoken.startTime = creds.issue_date;
+        atoken.endTime = (*pkrb_life_to_time)(creds.issue_date,creds.lifetime);
+        memcpy(&atoken.sessionKey, creds.session, 8);
+        atoken.ticketLen = creds.ticket_st.length;
+        memcpy(atoken.ticket, creds.ticket_st.dat, atoken.ticketLen);
+
+        if (tok_expiration)
+            *tok_expiration = atoken.endTime;
+
+        if (!(rc = ktc_GetToken(&aserver, &btoken, 
+                                sizeof(btoken), &aclient)) &&
+            atoken.kvno == btoken.kvno &&
+            atoken.ticketLen == btoken.ticketLen &&
+            !memcmp(&atoken.sessionKey, &btoken.sessionKey, 
+                    sizeof(atoken.sessionKey)) &&
+            !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen)) {
+
+            /* success! */
+            return(0);
+        }
+
+        // Reset the "aclient" structure before we call ktc_SetToken.
+        // This structure was first set by the ktc_GetToken call when
+        // we were comparing whether identical tokens already existed.
+
+        StringCchCopyA(aclient.name, MAXKTCNAMELEN, creds.pname);
+        if (creds.pinst[0]) {
+            StringCchCatA(aclient.name, MAXKTCNAMELEN, ".");
+            StringCchCatA(aclient.name, MAXKTCNAMELEN, creds.pinst);
+        }
+
+        StringCbCopyA(aclient.instance, sizeof(aclient.instance), "");
+
+        StringCchCatA(aclient.name, MAXKTCNAMELEN, "@");
+        StringCchCatA(aclient.name, MAXKTCNAMELEN, creds.realm);
+
+        StringCbCopyA(aclient.cell, sizeof(aclient.cell), CellName);
+
+        ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName, 
+                         &aclient, &aserver, &atoken);
+
+        // NOTE: On WIN32, the order of SetToken params changed...
+        // to   ktc_SetToken(&aserver, &aclient, &atoken, 0)
+        // from ktc_SetToken(&aserver, &atoken, &aclient, 0) on
+        // Unix...  The afscompat ktc_SetToken provides the Unix order
+
+        if (rc = ktc_SetToken(&aserver, &atoken, &aclient, 0)) {
+            afs_report_error(rc, "ktc_SetToken()");
+            return(rc);
+        }
+    } else if (method == AFS_TOKEN_AUTO ||
+               method >= AFS_TOKEN_USER) {
+        /* we couldn't get a token using Krb5, Krb524 or Krb4, either
+           because we couldn't get the necessary credentials or
+           because the method was set to not use those.  Now we
+           dispatch to any extensions to see if they have better
+           luck. */
+
+        rc = !afs_ext_klog(method,
+                           identity,
+                           ServiceName,
+                           CellName,
+                           RealmName,
+                           &ak_cellconfig,
+                           LifeTime);
+    } else {
+        /* if the return code was not set, we should set it now.
+           Otherwise we let the code go through. */
+        if (!rc) {
+            /* No tokens were obtained.  We should report something */
+            _report_sr1(KHERR_ERROR, IDS_ERR_GENERAL,
+                        _cptr(CellName));
+            _resolve();
+
+            rc = KHM_ERROR_GENERAL;
+        }
+    }
+
+    return rc;
+}
+
+/**************************************/
+/* afs_realm_of_cell():               */
+/**************************************/
+static char *
+afs_realm_of_cell(afs_conf_cell *cellconfig)
+{
+    char krbhst[MAX_HSTNM]="";
+    static char krbrlm[REALM_SZ+1]="";
+    krb5_context  ctx = 0;
+    char ** realmlist=NULL;
+    krb5_error_code r;
+
+    if (!cellconfig)
+        return 0;
+
+    if ( pkrb5_init_context ) {
+        r = pkrb5_init_context(&ctx); 
+        if ( !r )
+            r = pkrb5_get_host_realm(ctx, cellconfig->hostName[0], &realmlist);
+        if ( !r && realmlist && realmlist[0] ) {
+            StringCbCopyA(krbrlm, sizeof(krbrlm), realmlist[0]);
+            pkrb5_free_host_realm(ctx, realmlist);
+        }
+        if (ctx)
+            pkrb5_free_context(ctx);
+    }
+
+    if ( !krbrlm[0] ) {
+        StringCbCopyA(krbrlm, sizeof(krbrlm), 
+                      (char *)(*pkrb_realmofhost)(cellconfig->hostName[0]));
+        if ((*pkrb_get_krbhst)(krbhst, krbrlm, 1) != KSUCCESS)
+            krbrlm[0] = '\0';
+    }
+
+    if ( !krbrlm[0] ) {
+        char *s = krbrlm;
+        char *t = cellconfig->name;
+        int c;
+
+        while (c = *t++)
+        {
+            if (islower(c)) c=toupper(c);
+            *s++ = c;
+        }
+        *s++ = 0;
+    }
+    return(krbrlm);
+}
+
+/**************************************/
+/* afs_get_cellconfig():                  */
+/**************************************/
+static int 
+afs_get_cellconfig(char *cell, afs_conf_cell *cellconfig, char *local_cell)
+{
+    int        rc;
+    int ttl;
+
+    local_cell[0] = (char)0;
+    memset(cellconfig, 0, sizeof(*cellconfig));
+
+    cellconfig->cbsize = sizeof(*cellconfig);
+
+    /* WIN32: cm_GetRootCellName(local_cell) - NOTE: no way to get max chars */
+    if (rc = cm_GetRootCellName(local_cell)) {
+        return(rc);
+    }
+
+    if (strlen(cell) == 0)
+        StringCbCopyA(cell, (MAXCELLCHARS+1) * sizeof(char), local_cell);
+
+    /* WIN32: cm_SearchCellFile(cell, pcallback, pdata) */
+    StringCbCopyA(cellconfig->name, (MAXCELLCHARS+1) * sizeof(char), cell);
+
+    rc = cm_SearchCellFile(cell, NULL, afs_get_cellconfig_callback, 
+                           (void*)cellconfig);
+    if(rc)
+        rc = cm_SearchCellByDNS(cell, NULL, &ttl, 
+                                afs_get_cellconfig_callback, 
+                                (void*) cellconfig);
+
+    return rc;
+}
+
+/**************************************/
+/* afs_get_cellconfig_callback():          */
+/**************************************/
+static long 
+afs_get_cellconfig_callback(void *cellconfig, 
+                            struct sockaddr_in *addrp, 
+                            char *namep)
+{
+    afs_conf_cell *cc = (afs_conf_cell *)cellconfig;
+
+    cc->hostAddr[cc->numServers] = *addrp;
+    StringCbCopyA(cc->hostName[cc->numServers], 
+                  sizeof(cc->hostName[0]), namep);
+    cc->numServers++;
+    return(0);
+}
+
+
+/**************************************/
+/* afs_report_error():           */
+/**************************************/
+void
+afs_report_error(LONG rc, LPCSTR FailedFunctionName)
+{
+    char message[256];
+    const char *errText; 
+
+    // Using AFS defines as error messages for now, until Transarc 
+    // gets back to me with "string" translations of each of these 
+    // const. defines. 
+    if (rc == KTC_ERROR)
+        errText = "KTC_ERROR";
+    else if (rc == KTC_TOOBIG)
+        errText = "KTC_TOOBIG";
+    else if (rc == KTC_INVAL)
+        errText = "KTC_INVAL";
+    else if (rc == KTC_NOENT)
+        errText = "KTC_NOENT";
+    else if (rc == KTC_PIOCTLFAIL)
+        errText = "KTC_PIOCTLFAIL";
+    else if (rc == KTC_NOPIOCTL)
+        errText = "KTC_NOPIOCTL";
+    else if (rc == KTC_NOCELL)
+        errText = "KTC_NOCELL";
+    else if (rc == KTC_NOCM)
+        errText = "KTC_NOCM: The service, Transarc AFS Daemon, most likely is not started!";
+    else
+        errText = "Unknown error!";
+
+    StringCbPrintfA(message, sizeof(message), 
+                    "%s\n(%s failed)", errText, FailedFunctionName);
+    _report_cs1(KHERR_ERROR, L"%1!S!", _cptr(message));
+    _resolve();
+    return;
+}
+
+DWORD 
+GetServiceStatus(LPSTR lpszMachineName, 
+                 LPSTR lpszServiceName, 
+                 DWORD *lpdwCurrentState,
+                 DWORD *lpdwWaitHint) 
+{ 
+    DWORD           hr               = NOERROR; 
+    SC_HANDLE       schSCManager     = NULL; 
+    SC_HANDLE       schService       = NULL; 
+    DWORD           fdwDesiredAccess = 0; 
+    SERVICE_STATUS  ssServiceStatus  = {0}; 
+    BOOL            fRet             = FALSE; 
+
+    *lpdwCurrentState = 0; 
+    fdwDesiredAccess = GENERIC_READ; 
+    schSCManager = OpenSCManagerA(lpszMachineName,  
+                                  NULL,
+                                  fdwDesiredAccess); 
+    if(schSCManager == NULL) { 
+        hr = GetLastError();
+        goto cleanup; 
+    } 
+    schService = OpenServiceA(schSCManager,
+                              lpszServiceName,
+                              fdwDesiredAccess);
+    if(schService == NULL) { 
+        hr = GetLastError();
+        goto cleanup; 
+    } 
+    fRet = QueryServiceStatus(schService,
+                              &ssServiceStatus); 
+    if(fRet == FALSE) { 
+        hr = GetLastError(); 
+        goto cleanup; 
+    } 
+    *lpdwCurrentState = ssServiceStatus.dwCurrentState; 
+    if (lpdwWaitHint)
+        *lpdwWaitHint = ssServiceStatus.dwWaitHint;
+cleanup: 
+    CloseServiceHandle(schService); 
+    CloseServiceHandle(schSCManager); 
+    return(hr); 
+} 
+
+DWORD ServiceControl(LPSTR lpszMachineName, 
+                     LPSTR lpszServiceName,
+                     DWORD dwNewState) {
+
+    DWORD           hr               = NOERROR; 
+    SC_HANDLE       schSCManager     = NULL; 
+    SC_HANDLE       schService       = NULL; 
+    DWORD           fdwDesiredAccess = 0; 
+    SERVICE_STATUS  ssServiceStatus  = {0}; 
+    BOOL            fRet             = FALSE; 
+    DWORD           dwCurrentState   = 0;
+
+    dwCurrentState = 0; 
+    fdwDesiredAccess = GENERIC_READ;
+    schSCManager = OpenSCManagerA(lpszMachineName, NULL, 
+                                  fdwDesiredAccess); 
+    if(schSCManager == NULL) {
+        hr = GetLastError();
+        goto cleanup; 
+    }
+
+    fdwDesiredAccess = GENERIC_READ | GENERIC_EXECUTE;
+
+    schService = OpenServiceA(schSCManager, lpszServiceName,
+                              fdwDesiredAccess);
+    if(schService == NULL) {
+        hr = GetLastError();
+        goto cleanup; 
+    } 
+    fRet = QueryServiceStatus(schService, &ssServiceStatus);
+    if(fRet == FALSE) {
+        hr = GetLastError(); 
+        goto cleanup; 
+    } 
+    dwCurrentState = ssServiceStatus.dwCurrentState; 
+
+    if (dwCurrentState == SERVICE_STOPPED &&
+        dwNewState == SERVICE_RUNNING) {
+
+        fRet = StartService(schService, 0, NULL);
+
+        if (fRet == FALSE) {
+            hr = GetLastError();
+            goto cleanup;
+        }
+    }
+
+    if (dwCurrentState == SERVICE_RUNNING &&
+        dwNewState == SERVICE_STOPPED) {
+        fRet = ControlService(schService, SERVICE_CONTROL_STOP, 
+                              &ssServiceStatus);
+
+        if (fRet == FALSE) {
+            hr = GetLastError();
+            goto cleanup;
+        }
+    }
+cleanup: 
+    CloseServiceHandle(schService); 
+    CloseServiceHandle(schSCManager); 
+    return(hr); 
+}
diff --git a/src/WINNT/netidmgr_plugin/afsfuncs.h b/src/WINNT/netidmgr_plugin/afsfuncs.h
new file mode 100644 (file)
index 0000000..6a163cd
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2004 Massachusetts Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* $Id$ */
+
+#ifndef __KHIMAIRA_AFSFUNCS_H
+#define __KHIMAIRA_AFSFUNCS_H
+
+
+BOOL
+afs_is_running(void);
+
+int 
+afs_princ_to_string(struct ktc_principal * p, wchar_t * buf, size_t cbbuf);
+
+int 
+afs_list_tokens(void);
+
+khm_handle
+afs_find_token(khm_handle credset, wchar_t * cell);
+
+int 
+afs_list_tokens_internal(void);
+
+int 
+afs_klog(khm_handle identity,
+         char *service,
+         char *cell,
+         char *realm,
+         int LifeTime,
+         afs_tk_method method,
+         time_t * tok_expiration /* OUT: expiration time of new
+                                    token */
+         );
+
+int
+afs_unlog(void);
+
+int
+afs_unlog_cred(khm_handle cred);
+
+DWORD 
+GetServiceStatus(LPSTR lpszMachineName, 
+                 LPSTR lpszServiceName, 
+                 DWORD *lpdwCurrentState,
+                 DWORD *lpdwWaitHint);
+
+DWORD 
+ServiceControl(LPSTR lpszMachineName, 
+               LPSTR lpszServiceName,
+               DWORD dwNewState);
+
+void afs_report_error(LONG rc, LPCSTR FailedFunctionName);
+
+static char *afs_realm_of_cell(afs_conf_cell *);
+static long afs_get_cellconfig_callback(void *, struct sockaddr_in *, char *);
+static int afs_get_cellconfig(char *, afs_conf_cell *, char *);
+
+#endif
diff --git a/src/WINNT/netidmgr_plugin/afshelp.c b/src/WINNT/netidmgr_plugin/afshelp.c
new file mode 100644 (file)
index 0000000..e143c06
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2004 Massachusetts Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* $Id$ */
+
+#define NOSTRSAFE
+
+#include<afscred.h>
+#include<shlwapi.h>
+#include<htmlhelp.h>
+#include<psapi.h>
+
+#ifdef DEBUG
+#include<assert.h>
+#endif
+
+#include<strsafe.h>
+
+static wchar_t helpfile[MAX_PATH] = L"";
+
+/* can only be called from the UI thread */
+HWND
+afs_html_help(HWND caller,
+              wchar_t * postfix,
+              UINT cmd,
+              DWORD_PTR data) {
+
+    wchar_t fullp[MAX_PATH + MAX_PATH];
+
+    if (!helpfile[0]) {
+        DWORD rv;
+
+        rv = GetModuleFileNameEx(GetCurrentProcess(),
+                                 hInstance,
+                                 helpfile,
+                                 ARRAYLENGTH(helpfile));
+#ifdef DEBUG
+        assert(rv != 0);
+#endif
+        PathRemoveFileSpec(helpfile);
+        PathAppend(helpfile, AFS_HELPFILE);
+    }
+
+    StringCbCopy(fullp, sizeof(fullp), helpfile);
+    if (postfix)
+        StringCbCat(fullp, sizeof(fullp), postfix);
+
+    return HtmlHelp(caller, fullp, cmd, data);
+}
diff --git a/src/WINNT/netidmgr_plugin/afsnewcreds.c b/src/WINNT/netidmgr_plugin/afsnewcreds.c
new file mode 100644 (file)
index 0000000..e35c347
--- /dev/null
@@ -0,0 +1,2781 @@
+/*
+ * Copyright (c) 2004 Massachusetts Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* $Id$ */
+
+#include<afscred.h>
+#include<commctrl.h>
+#include<assert.h>
+#include<netidmgr_version.h>
+#include<htmlhelp.h>
+#include<help/afsplhlp.h>
+
+/* UI stuff */
+
+#define WMNC_AFS_UPDATE_ROWS (WMNC_USER + 1)
+
+typedef struct tag_afs_ident_token_set {
+    khm_handle ident;
+    afs_cred_list * l;
+    khm_boolean add_new;
+    khm_boolean update_info;
+} afs_ident_token_set;
+
+
+void 
+afs_cred_flush_rows(afs_cred_list * l) {
+    int i;
+
+    for(i=0; i<l->n_rows; i++) {
+        if(l->rows[i].cell)
+            PFREE(l->rows[i].cell);
+        if(l->rows[i].realm)
+            PFREE(l->rows[i].realm);
+    }
+
+    if(l->nc_rows) {
+        ZeroMemory(l->rows, sizeof(l->rows[0]) * l->nc_rows);
+    }
+
+    l->n_rows = 0;
+}
+
+void 
+afs_cred_free_rows(afs_cred_list * l) {
+
+    afs_cred_flush_rows(l);
+
+    if(l->rows)
+        PFREE(l->rows);
+    l->rows = NULL;
+    l->n_rows = 0;
+    l->nc_rows = 0;
+}
+
+void 
+afs_cred_assert_rows(afs_cred_list * l, int n) {
+    afs_cred_row * rows;
+
+    if(n > l->nc_rows) {
+        l->nc_rows = UBOUNDSS(n, AFS_DLG_ROW_ALLOC, AFS_DLG_ROW_ALLOC);
+        rows = PMALLOC(sizeof(afs_cred_row) * l->nc_rows);
+        ZeroMemory(rows, sizeof(afs_cred_row) * l->nc_rows);
+
+        if(l->rows) {
+            if(l->n_rows)
+                memcpy(rows, l->rows, sizeof(afs_cred_row) * l->n_rows);
+            PFREE(l->rows);
+        }
+        l->rows = rows;
+    }
+}
+
+void 
+afs_cred_delete_row(afs_cred_list * l, int i) {
+    if (i < 0 || i >= l->n_rows)
+        return;
+
+    if(i < (l->n_rows - 1)) {
+        if(l->rows[i].cell)
+            PFREE(l->rows[i].cell);
+        if(l->rows[i].realm)
+            PFREE(l->rows[i].realm);
+        memmove(&(l->rows[i]),
+                &(l->rows[i+1]),
+                ((l->n_rows - (i+1)) * 
+                 sizeof(l->rows[0])));
+    }
+    l->n_rows--;
+}
+
+afs_cred_row * 
+afs_cred_get_new_row(afs_cred_list * l) {
+    afs_cred_row * r;
+
+    afs_cred_assert_rows(l, l->n_rows + 1);
+    r = &(l->rows[l->n_rows]);
+    l->n_rows++;
+
+    ZeroMemory(r, sizeof(*r));
+
+    return r;
+}
+
+afs_cred_row *
+afs_cred_add_row_from_cred(afs_cred_list * l,
+                           khm_handle cred) {
+    khm_int32 rv;
+    afs_cred_row * row;
+    khm_size cb;
+    wchar_t cell[MAXCELLCHARS];
+    int i;
+
+    cb = sizeof(cell);
+    rv = kcdb_cred_get_attr(cred,
+                            afs_attr_cell,
+                            NULL,
+                            cell,
+                            &cb);
+#ifdef DEBUG
+    assert(rv == KHM_ERROR_SUCCESS && cb != 0);
+#endif
+
+    /* check if we already have the cell listed. */
+    for (i=0; i<l->n_rows; i++) {
+        if (!_wcsicmp(l->rows[i].cell, cell))
+            return &l->rows[i];
+    }
+
+    row = afs_cred_get_new_row(l);
+
+    row->cell = PMALLOC(cb);
+    StringCbCopy(row->cell, cb, cell);
+
+    cb = sizeof(row->method);
+    rv = kcdb_cred_get_attr(cred,
+                            afs_attr_method,
+                            NULL,
+                            &row->method,
+                            &cb);
+
+    if (KHM_FAILED(rv)) {
+        row->method = AFS_TOKEN_AUTO;
+        row->realm = NULL;
+        return row;
+    }
+
+    rv = kcdb_cred_get_attr(cred,
+                            afs_attr_realm,
+                            NULL,
+                            NULL,
+                            &cb);
+
+    if (rv == KHM_ERROR_TOO_LONG && cb > sizeof(wchar_t)) {
+        row->realm = PMALLOC(cb);
+#ifdef DEBUG
+        assert(row->realm);
+#endif
+        rv = kcdb_cred_get_attr(cred,
+                                afs_attr_realm,
+                                NULL,
+                                row->realm,
+                                &cb);
+
+        if (KHM_FAILED(rv)) {
+            if (row->realm)
+                PFREE(row->realm);
+            row->realm = NULL;
+        }
+    } else {
+        row->realm = NULL;
+    }
+
+    return row;
+}
+
+khm_int32 KHMAPI
+afs_cred_add_cred_proc(khm_handle cred, void * rock) {
+    afs_cred_list * l = (afs_cred_list *) rock;
+    khm_int32 t;
+
+    if (KHM_FAILED(kcdb_cred_get_type(cred, &t)) ||
+        t != afs_credtype_id)
+        return KHM_ERROR_SUCCESS;
+
+    afs_cred_add_row_from_cred(l, cred);
+
+    return KHM_ERROR_SUCCESS;
+}
+
+void
+afs_cred_get_context_creds(afs_cred_list *l,
+                           khui_action_context * ctx) {
+    khm_handle credset = NULL;
+
+    if (KHM_FAILED(kcdb_credset_create(&credset)))
+        return;
+
+    if (KHM_FAILED(kcdb_credset_extract_filtered(credset,
+                                                 NULL,
+                                                 khui_context_cursor_filter,
+                                                 (void *) ctx)))
+        goto _cleanup;
+
+    kcdb_credset_apply(credset,
+                       afs_cred_add_cred_proc,
+                       (void *) l);
+
+ _cleanup:
+    if (credset)
+        kcdb_credset_delete(credset);
+}
+
+khm_int32 KHMAPI
+afs_get_id_creds_apply_proc(khm_handle cred, void * rock) {
+    khm_int32 t;
+    afs_ident_token_set * ts;
+    afs_cred_list * l;
+    khm_handle ident;
+    wchar_t cell[MAXCELLCHARS];
+    khm_size cb;
+    int i;
+    khm_int32 cflags = 0;
+
+    ts = (afs_ident_token_set *) rock;
+    l = ts->l;
+
+    kcdb_cred_get_type(cred, &t);
+    if (t != afs_credtype_id)
+        return KHM_ERROR_SUCCESS;
+
+    cb = sizeof(cell);
+    if (KHM_FAILED(kcdb_cred_get_attr(cred, afs_attr_cell,
+                                      NULL,
+                                      cell, &cb)))
+        return KHM_ERROR_SUCCESS;
+
+    kcdb_cred_get_flags(cred, &cflags);
+
+    kcdb_cred_get_identity(cred, &ident);
+
+    if (kcdb_identity_is_equal(ident, ts->ident)) {
+
+        for (i=0; i < l->n_rows; i++) {
+            if (!_wcsicmp(l->rows[i].cell, cell)) {
+                khm_int32 method;
+
+                /* if the token exists, then these are implied */
+                l->rows[i].flags =
+                    DLGROW_FLAG_EXISTS |
+                    DLGROW_FLAG_CHECKED |
+                    DLGROW_FLAG_VALID;
+
+                if (cflags & KCDB_CRED_FLAG_EXPIRED)
+                    l->rows[i].flags |= DLGROW_FLAG_EXPIRED;
+
+                if (ts->update_info) {
+                    wchar_t realm[KHUI_MAXCCH_NAME];
+
+                    cb = sizeof(method);
+                    if (KHM_SUCCEEDED
+                        (kcdb_cred_get_attr(cred, afs_attr_method,
+                                            NULL,
+                                            &method, &cb)) &&
+                        afs_is_valid_method_id(method))
+                        l->rows[i].method = method;
+
+                    cb = sizeof(realm);
+                    if (KHM_SUCCEEDED
+                        (kcdb_cred_get_attr(cred, afs_attr_realm,
+                                            NULL,
+                                            realm, &cb)) &&
+                        cb > sizeof(wchar_t)) {
+
+                        if (l->rows[i].realm)
+                            PFREE(l->rows[i].realm);
+                        l->rows[i].realm = PMALLOC(cb);
+                        StringCbCopy(l->rows[i].realm,
+                                     cb,
+                                     realm);
+                    }
+                }
+                break;
+            }
+        }
+
+        /* not found? add! */
+        if (i >= l->n_rows && ts->add_new) {
+            afs_cred_row * r;
+
+            r = afs_cred_add_row_from_cred(l, cred);
+
+            r->flags = DLGROW_FLAG_VALID | DLGROW_FLAG_CHECKED |
+                DLGROW_FLAG_EXISTS;
+
+            if (cflags & KCDB_CRED_FLAG_EXPIRED)
+                r->flags |= DLGROW_FLAG_EXPIRED;
+        }
+
+    } else {                    /* different identities */
+
+        for (i=0; i < l->n_rows; i++) {
+            if (!_wcsicmp(l->rows[i].cell, cell)) {
+                l->rows[i].flags =
+                    DLGROW_FLAG_NOTOWNED | DLGROW_FLAG_EXISTS |
+                    DLGROW_FLAG_VALID | DLGROW_FLAG_CHECKED;
+                if (cflags & KCDB_CRED_FLAG_EXPIRED)
+                    l->rows[i].flags |= DLGROW_FLAG_EXPIRED;
+            }
+        }
+
+    }
+
+    kcdb_identity_release(ident);
+
+    return KHM_ERROR_SUCCESS;
+}
+
+void
+afs_remove_token_from_identities(wchar_t * cell) {
+    wchar_t * idents = NULL;
+    wchar_t * t;
+    khm_size cb_id;
+    khm_size n_id = 0;
+
+    do {
+        if (kcdb_identity_enum(KCDB_IDENT_FLAG_CONFIG,
+                               KCDB_IDENT_FLAG_CONFIG,
+                               NULL,
+                               &cb_id,
+                               &n_id) != KHM_ERROR_TOO_LONG ||
+            n_id == 0) {
+            if (idents)
+                PFREE(idents);
+            return;
+        }
+
+        if (idents)
+            PFREE(idents);
+        idents = PMALLOC(cb_id);
+
+        if (kcdb_identity_enum(KCDB_IDENT_FLAG_CONFIG,
+                               KCDB_IDENT_FLAG_CONFIG,
+                               idents,
+                               &cb_id,
+                               &n_id) == KHM_ERROR_SUCCESS)
+            break;
+    } while(TRUE);
+
+    for (t=idents;
+         t && *t;
+         t = multi_string_next(t)) {
+
+        khm_handle h_id = NULL;
+        khm_handle csp_ident = NULL;
+        khm_handle csp_afs = NULL;
+        khm_size cb;
+        wchar_t vbuf[1024];
+        wchar_t * tbuf = NULL;
+
+        kcdb_identity_create(t, 0, &h_id);
+        if (h_id == NULL) {
+#ifdef DEBUG
+            assert(FALSE);
+#endif
+            continue;
+        }
+
+        if (KHM_FAILED(kcdb_identity_get_config(h_id, 0, &csp_ident)))
+            goto _cleanup_loop;
+
+        if (KHM_FAILED(khc_open_space(csp_ident, CSNAME_AFSCRED,
+                                      0, &csp_afs)))
+            goto _cleanup_loop;
+
+        if (khc_read_multi_string(csp_afs, L"Cells", NULL, &cb)
+            != KHM_ERROR_TOO_LONG)
+            goto _cleanup_loop;
+
+        if (cb < sizeof(vbuf))
+            tbuf = vbuf;
+        else
+            tbuf = PMALLOC(cb);
+
+        if (khc_read_multi_string(csp_afs, L"Cells", tbuf, &cb)
+            != KHM_ERROR_SUCCESS)
+            goto _cleanup_loop;
+
+        if (multi_string_find(tbuf, cell, 0) == NULL)
+            goto _cleanup_loop;
+
+        multi_string_delete(tbuf, cell, 0);
+
+        khc_write_multi_string(csp_afs, L"Cells", tbuf);
+
+    _cleanup_loop:
+        kcdb_identity_release(h_id);
+        if (csp_ident)
+            khc_close_space(csp_ident);
+        if (csp_afs)
+            khc_close_space(csp_afs);
+        if (tbuf && tbuf != vbuf)
+            PFREE(tbuf);
+    }
+
+    if (idents)
+        PFREE(idents);
+}
+
+khm_boolean
+afs_check_add_token_to_identity(wchar_t * cell, khm_handle ident,
+                                khm_handle * ident_conflict) {
+    wchar_t * idents = NULL;
+    wchar_t * t;
+    khm_size cb_id;
+    khm_size n_id = 0;
+    khm_boolean ok_to_add = TRUE;
+
+    /* check if this cell is listed for any other identity. */
+
+    do {
+        if (kcdb_identity_enum(KCDB_IDENT_FLAG_CONFIG,
+                               KCDB_IDENT_FLAG_CONFIG,
+                               NULL,
+                               &cb_id,
+                               &n_id) != KHM_ERROR_TOO_LONG ||
+            n_id == 0) {
+            if (idents)
+                PFREE(idents);
+            return TRUE;
+        }
+
+        if (idents)
+            PFREE(idents);
+        idents = PMALLOC(cb_id);
+
+        if (kcdb_identity_enum(KCDB_IDENT_FLAG_CONFIG,
+                               KCDB_IDENT_FLAG_CONFIG,
+                               idents,
+                               &cb_id,
+                               &n_id) == KHM_ERROR_SUCCESS)
+            break;
+    } while(TRUE);
+
+    for (t=idents;
+         ok_to_add && t && *t;
+         t = multi_string_next(t)) {
+
+        khm_handle h_id = NULL;
+        khm_handle csp_ident = NULL;
+        khm_handle csp_afs = NULL;
+        khm_size cb;
+        wchar_t vbuf[1024];
+        wchar_t * tbuf = NULL;
+
+        kcdb_identity_create(t, 0, &h_id);
+        if (h_id == NULL) {
+#ifdef DEBUG
+            assert(FALSE);
+#endif
+            continue;
+        }
+
+        if (kcdb_identity_is_equal(h_id, ident)) {
+            kcdb_identity_release(h_id);
+            continue;
+        }
+
+        if (KHM_FAILED(kcdb_identity_get_config(h_id, 0, &csp_ident)))
+            goto _cleanup_loop;
+
+        if (KHM_FAILED(khc_open_space(csp_ident, CSNAME_AFSCRED,
+                                      0, &csp_afs)))
+            goto _cleanup_loop;
+
+        if (khc_read_multi_string(csp_afs, L"Cells", NULL, &cb)
+            != KHM_ERROR_TOO_LONG)
+            goto _cleanup_loop;
+
+        if (cb < sizeof(vbuf))
+            tbuf = vbuf;
+        else
+            tbuf = PMALLOC(cb);
+
+        if (khc_read_multi_string(csp_afs, L"Cells", tbuf, &cb)
+            != KHM_ERROR_SUCCESS)
+            goto _cleanup_loop;
+
+        if (multi_string_find(tbuf, cell, 0) == NULL)
+            goto _cleanup_loop;
+
+        /* we found another identity which gets tokens for the
+           same cell */
+
+        ok_to_add = FALSE;
+
+        if (ident_conflict) {
+            *ident_conflict = h_id;
+            kcdb_identity_hold(h_id);
+        }
+
+    _cleanup_loop:
+        kcdb_identity_release(h_id);
+        if (csp_ident)
+            khc_close_space(csp_ident);
+        if (csp_afs)
+            khc_close_space(csp_afs);
+        if (tbuf && tbuf != vbuf)
+            PFREE(tbuf);
+    }
+
+    if (idents)
+        PFREE(idents);
+
+    return ok_to_add;
+}
+
+void 
+afs_cred_get_identity_creds(afs_cred_list * l, 
+                            khm_handle ident,
+                            khm_boolean * penabled) {
+    khm_handle h_id = NULL;
+    khm_handle h_afs = NULL;
+    khm_handle h_cells = NULL;  /* per identity cells space */
+    khm_handle h_gcells = NULL; /* global cells space */
+    khm_boolean load_defs = TRUE;
+    khm_size cbi;
+    wchar_t * ms = NULL;
+    wchar_t * s = NULL;
+    afs_ident_token_set ts;
+    khm_int32 t;
+
+    if (penabled)
+        *penabled = TRUE;
+
+    afs_cred_flush_rows(l);
+
+    kcdb_identity_get_config(ident, 0, &h_id);
+    if(!h_id) 
+        goto _done_config;
+
+    if(KHM_FAILED(khc_open_space(h_id, CSNAME_AFSCRED, 
+                                 0, &h_afs)))
+        goto _done_config;
+
+    if (penabled) {
+        t = 1;
+        if (KHM_FAILED(khc_read_int32(h_afs, L"AFSEnabled", &t)))
+            khc_read_int32(csp_params, L"AFSEnabled", &t);
+        *penabled = !!t;
+    }
+
+    if(KHM_FAILED(khc_open_space(h_afs, L"Cells", 
+                                 0, &h_cells)))
+        goto _done_config;
+
+    if(khc_read_multi_string(h_afs, L"Cells", NULL, &cbi) != 
+       KHM_ERROR_TOO_LONG)
+        goto _done_config;
+
+    load_defs = FALSE;
+
+    ms = PMALLOC(cbi);
+    ZeroMemory(ms, cbi);
+
+    khc_read_multi_string(h_afs, L"Cells", ms, &cbi);
+
+    s = ms;
+    for(s = ms; s && *s; s = multi_string_next(s)) {
+        afs_cred_row * r;
+        size_t cb;
+        khm_handle h_cell = NULL;
+
+        /* is this a valid cell name? */
+        if(FAILED(StringCbLength(s, MAXCELLCHARS, &cb)))
+            continue;
+        cb += sizeof(wchar_t);
+
+        r = afs_cred_get_new_row(l);
+
+        r->cell = PMALLOC(cb);
+        StringCbCopy(r->cell, cb, s);
+
+        r->realm = NULL;
+        r->method = 0;
+        r->flags = 0;
+
+        if(KHM_SUCCEEDED(khc_open_space(h_cells, s, 
+                                        0, &h_cell))) {
+            khm_int32 i;
+            wchar_t wname[KHUI_MAXCCH_NAME];
+            khm_size cb;
+
+            if(khc_read_string(h_cell, L"Realm", 
+                               NULL, &cbi) == 
+               KHM_ERROR_TOO_LONG &&
+               cbi > sizeof(wchar_t)) {
+
+                r->realm = PMALLOC(cbi);
+                khc_read_string(h_cell, L"Realm", r->realm, &cbi);
+            }
+
+            i = AFS_TOKEN_AUTO;
+
+            cb = sizeof(wname);
+            if (KHM_SUCCEEDED(khc_read_string(h_cell, L"MethodName",
+                                              wname, &cb))) {
+
+                r->method = afs_get_method_id(wname);
+
+                /* remove the deprecated value if it is present. */
+                khc_remove_value(h_cell, L"Method", 0);
+
+            } else if (KHM_SUCCEEDED(khc_read_int32(h_cell, 
+                                                    L"Method", &i))) {
+                /* the Method property is deprecated.  We detect and
+                   correct this whenever possible. */
+
+                if (!afs_is_valid_method_id(i))
+                    i = AFS_TOKEN_AUTO;
+
+                r->method = i;
+
+                afs_get_method_name(i, wname, sizeof(wname));
+
+                khc_write_string(h_cell, L"MethodName",
+                                 wname);
+
+                khc_remove_value(h_cell, L"Method", 0);
+            }
+
+            khc_close_space(h_cell);
+        }
+    }
+
+    if(ms) {
+        PFREE(ms);
+        ms = NULL;
+    }
+
+ _done_config:
+
+    if (load_defs) {
+        /* We want to load defaults */
+        char buf[MAXCELLCHARS];
+        wchar_t wbuf[MAXCELLCHARS];
+        wchar_t wmethod[KHUI_MAXCCH_NAME];
+        wchar_t * defcells;
+        khm_size cb_defcells;
+        afs_cred_row * r;
+        khm_size sz;
+
+        khc_open_space(csp_params, L"Cells", 0, &h_gcells);
+
+        if(!cm_GetRootCellName(buf)) {
+            AnsiStrToUnicode(wbuf, sizeof(wbuf), buf);
+
+            if (afs_check_add_token_to_identity(wbuf, ident, NULL)) {
+                khm_handle h_cell = NULL;
+
+                r = afs_cred_get_new_row(l);
+
+                StringCbLength(wbuf, sizeof(wbuf), &sz);
+                sz += sizeof(wchar_t);
+
+                r->cell = PMALLOC(sz);
+                StringCbCopy(r->cell, sz, wbuf);
+
+                if (h_gcells &&
+                    KHM_SUCCEEDED(khc_open_space(h_gcells, wbuf, 0, &h_cell))) {
+                    khm_size cb;
+
+                    cb = sizeof(wmethod);
+                    if (KHM_SUCCEEDED(khc_read_string(h_cell, L"MethodName", wmethod, &cb))) {
+                        r->method = afs_get_method_id(wmethod);
+                    } else {
+                        r->method = AFS_TOKEN_AUTO;
+                    }
+
+                    cb = sizeof(wbuf);
+                    if (KHM_SUCCEEDED(khc_read_string(h_cell, L"Realm", wbuf, &cb))) {
+                        r->realm = PMALLOC(cb);
+                        StringCbCopy(r->realm, cb, wbuf);
+                    } else {
+                        r->realm = NULL;
+                    }
+
+                    khc_close_space(h_cell);
+
+                } else {
+                    r->realm = NULL;
+                    r->method = AFS_TOKEN_AUTO;
+                }
+
+                r->flags = 0;
+            }
+        }
+
+        if (khc_read_multi_string(csp_params, L"DefaultCells",
+                                  NULL, &cb_defcells) == KHM_ERROR_TOO_LONG &&
+            cb_defcells > sizeof(wchar_t) * 2) {
+            wchar_t * c_cell;
+
+            defcells = PMALLOC(cb_defcells);
+            if (defcells == NULL)
+                goto _done_defaults;
+
+            if (KHM_FAILED(khc_read_multi_string(csp_params, L"DefaultCells",
+                                                 defcells, &cb_defcells))) {
+                PFREE(defcells);
+                goto _done_defaults;
+            }
+
+            for (c_cell = defcells;
+                 c_cell && *c_cell;
+                 c_cell = multi_string_next(c_cell)) {
+
+                khm_size cb;
+                int i;
+                khm_handle h_cell = NULL;
+                afs_cred_row * r;
+
+                if (FAILED(StringCbLength(c_cell, (MAXCELLCHARS + 1) * sizeof(wchar_t),
+                                          &cb)))
+                    continue;
+                cb += sizeof(wchar_t);
+
+                for (i=0; i < l->n_rows; i++) {
+                    if (!_wcsicmp(l->rows[i].cell, c_cell))
+                        break;
+                }
+
+                if (i < l->n_rows)
+                    continue;
+
+                r = afs_cred_get_new_row(l);
+
+                r->cell = PMALLOC(cb);
+                StringCbCopy(r->cell, cb, c_cell);
+
+                if (h_gcells &&
+                    KHM_SUCCEEDED(khc_open_space(h_gcells, c_cell, 0, &h_cell))) {
+
+                    cb = sizeof(wmethod);
+                    if (KHM_SUCCEEDED(khc_read_string(h_cell, L"MethodName", wmethod, &cb))) {
+                        r->method = afs_get_method_id(wmethod);
+                    } else {
+                        r->method = AFS_TOKEN_AUTO;
+                    }
+
+                    cb = sizeof(wbuf);
+                    if (KHM_SUCCEEDED(khc_read_string(h_cell, L"Realm", wbuf, &cb))) {
+                        r->realm = PMALLOC(cb);
+                        StringCbCopy(r->realm, cb, wbuf);
+                    } else {
+                        r->realm = NULL;
+                    }
+
+                    khc_close_space(h_cell);
+                } else {
+                    r->realm = NULL;
+                    r->method = AFS_TOKEN_AUTO;
+                }
+
+                r->flags = 0;
+            }
+
+            PFREE(defcells);
+        }
+    }
+
+ _done_defaults:
+
+    ts.ident = ident;
+    ts.l = l;
+    ts.add_new = TRUE;
+    ts.update_info = FALSE;
+
+    kcdb_credset_apply(NULL, afs_get_id_creds_apply_proc,
+                       &ts);
+
+    if(h_id)
+        khc_close_space(h_id);
+    if(h_afs)
+        khc_close_space(h_afs);
+    if(h_cells)
+        khc_close_space(h_cells);
+    if(h_gcells)
+        khc_close_space(h_gcells);
+}
+
+void 
+nc_dlg_enable(HWND hwnd, BOOL enable) {
+    if(enable) {
+        SendDlgItemMessage(hwnd, IDC_NCAFS_OBTAIN, BM_SETCHECK, 
+                           BST_CHECKED, 0);
+    } else {
+        SendDlgItemMessage(hwnd, IDC_NCAFS_OBTAIN, BM_SETCHECK, 
+                           BST_UNCHECKED, 0);
+    }
+
+    EnableWindow(GetDlgItem(hwnd,IDC_NCAFS_CELL), enable);
+    EnableWindow(GetDlgItem(hwnd,IDC_NCAFS_REALM), enable);
+    EnableWindow(GetDlgItem(hwnd,IDC_NCAFS_METHOD), enable);
+    EnableWindow(GetDlgItem(hwnd,IDC_NCAFS_TOKENLIST), enable);
+    EnableWindow(GetDlgItem(hwnd,IDC_NCAFS_ADD_TOKEN), enable);
+    EnableWindow(GetDlgItem(hwnd,IDC_NCAFS_DELETE_TOKEN), enable);
+}
+
+void 
+nc_dlg_show_tooltip(HWND hwnd, 
+                    UINT_PTR id, 
+                    LPWSTR msg, 
+                    LPWSTR title, 
+                    int type, 
+                    int x, 
+                    int y)
+{
+    afs_dlg_data * d;
+    TOOLINFO ti;
+
+    d = (afs_dlg_data *)(LONG_PTR) GetWindowLongPtr(hwnd, DWLP_USER);
+
+    ZeroMemory(&ti, sizeof(ti));
+    ti.cbSize = sizeof(ti);
+    ti.hwnd = hwnd;
+    ti.uId = id;
+    SendMessage(d->tooltip, TTM_GETTOOLINFO, 0, (LPARAM) &ti);
+
+    ti.hinst = hResModule;
+    ti.lpszText = msg;
+
+    SendMessage(d->tooltip, TTM_SETTOOLINFO, 0, (LPARAM) &ti);
+
+    if(IS_INTRESOURCE(title)) {
+        wchar_t wbuf[1024];
+        UINT resid;
+
+        resid = (UINT)(UINT_PTR) title;
+
+        LoadString(hResModule, resid, wbuf, ARRAYLENGTH(wbuf));
+        SendMessage(d->tooltip, TTM_SETTITLE, type, (LPARAM) wbuf);
+    } else
+        SendMessage(d->tooltip, TTM_SETTITLE, type, (LPARAM) title);
+
+    SendMessage(d->tooltip, TTM_TRACKACTIVATE, TRUE, (LPARAM) &ti);
+    SendMessage(d->tooltip, TTM_TRACKPOSITION, 0, (LPARAM) MAKELONG(x,y));
+
+    d->tooltip_visible = TRUE;
+
+    SetTimer(hwnd, DLG_TOOLTIP_TIMER_ID, DLG_TOOLTIP_TIMEOUT, NULL);
+}
+
+void 
+nc_dlg_hide_tooltip(HWND hwnd, UINT_PTR id)
+{
+    TOOLINFO ti;
+    afs_dlg_data * d;
+
+    d = (afs_dlg_data *)(LONG_PTR) GetWindowLongPtr(hwnd, DWLP_USER);
+
+    if(!d->tooltip_visible)
+        return;
+
+    ZeroMemory(&ti, sizeof(ti));
+    ti.cbSize = sizeof(ti);
+    ti.hwnd = hwnd;
+    ti.uId = id;
+
+    SendMessage(d->tooltip, TTM_TRACKACTIVATE, FALSE, (LPARAM) &ti);
+    d->tooltip_visible = FALSE;
+}
+
+void 
+afs_dlg_update_rows(HWND hwnd, afs_dlg_data * d) {
+    HWND hwlist;
+    LVITEM lvi;
+    wchar_t wauto[256];
+    int i;
+
+    CheckDlgButton(hwnd, IDC_NCAFS_OBTAIN,
+                   (d->afs_enabled)? BST_CHECKED: BST_UNCHECKED);
+
+    hwlist = GetDlgItem(hwnd, IDC_NCAFS_TOKENLIST);
+
+    ListView_DeleteAllItems(hwlist);
+
+    if(d->creds.n_rows == 0)
+        return;
+
+    LoadString(hResModule, IDS_NC_AUTO, wauto, ARRAYLENGTH(wauto));
+
+    for(i=0; i < d->creds.n_rows; i++) {
+        wchar_t wbuf[256];
+        int flags;
+
+        ZeroMemory(&lvi, sizeof(lvi));
+
+        lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE;
+        lvi.iItem = d->creds.n_rows + 1;
+
+        lvi.stateMask = LVIS_STATEIMAGEMASK;
+        flags = d->creds.rows[i].flags;
+        if ((flags & DLGROW_FLAG_EXISTS) &&
+            (flags & DLGROW_FLAG_NOTOWNED)) {
+            lvi.state = INDEXTOSTATEIMAGEMASK(d->idx_bad_token);
+        } else if ((flags & DLGROW_FLAG_EXISTS)) {
+            lvi.state = INDEXTOSTATEIMAGEMASK(d->idx_existing_token);
+        } else {
+            lvi.state = INDEXTOSTATEIMAGEMASK(d->idx_new_token);
+        }
+
+        lvi.lParam = (LPARAM) i;
+
+        lvi.iSubItem = NCAFS_IDX_CELL;
+        lvi.pszText = d->creds.rows[i].cell;
+
+        lvi.iItem = ListView_InsertItem(hwlist, &lvi);
+
+        lvi.mask = LVIF_TEXT; /* subitems dislike lParam */
+        lvi.iSubItem = NCAFS_IDX_REALM;
+        if(d->creds.rows[i].realm != NULL)
+            lvi.pszText = d->creds.rows[i].realm;
+        else
+            lvi.pszText = wauto;
+        ListView_SetItem(hwlist, &lvi);
+
+        lvi.iSubItem = NCAFS_IDX_METHOD;
+        afs_method_describe(d->creds.rows[i].method,
+                            KCDB_TS_SHORT,
+                            wbuf, sizeof(wbuf));
+        lvi.pszText = wbuf;
+
+        ListView_SetItem(hwlist, &lvi);
+    }
+}
+
+void 
+nc_dlg_del_token(HWND hwnd) {
+    afs_dlg_data * d;
+    khui_new_creds_by_type * nct;
+
+    d = (afs_dlg_data *)(LONG_PTR) GetWindowLongPtr(hwnd, DWLP_USER);
+
+    if (d->nc)
+        khui_cw_find_type(d->nc, afs_credtype_id, &nct);
+
+    if(ListView_GetSelectedCount(GetDlgItem(hwnd, IDC_NCAFS_TOKENLIST)) == 0) {
+        wchar_t cell[KCDB_MAXCCH_NAME];
+        int i;
+
+        /* nothing is selected in the list view */
+        /* we delete the row that matches the current contents of the
+        cell edit control */
+        cell[0] = 0;
+        GetDlgItemText(hwnd, IDC_NCAFS_CELL, cell, ARRAYLENGTH(cell));
+        for(i=0; i<d->creds.n_rows; i++) {
+            if(!_wcsicmp(d->creds.rows[i].cell, cell)) {
+                /* found it */
+                afs_cred_delete_row(&d->creds, i);
+                afs_dlg_update_rows(hwnd, d);
+                d->dirty = TRUE;
+                break;
+            }
+        }
+    } else {
+        /* something is selected in the token list view */
+        /* we delete that */
+        HWND hw;
+        LVITEM lvi;
+        int idx;
+        int row;
+        BOOL deleted = FALSE;
+
+        hw = GetDlgItem(hwnd, IDC_NCAFS_TOKENLIST);
+        idx = -1;
+        do {
+            idx = ListView_GetNextItem(hw, idx, LVNI_SELECTED);
+            if(idx >= 0) {
+                ZeroMemory(&lvi, sizeof(lvi));
+                lvi.iItem = idx;
+                lvi.iSubItem = 0;
+                lvi.mask = LVIF_PARAM;
+                if(!ListView_GetItem(hw, &lvi))
+                    continue;
+                row = (int) lvi.lParam;
+                if(row >= 0 && row < d->creds.n_rows) {
+                    d->creds.rows[row].flags |= DLGROW_FLAG_DELETED;
+                    deleted = TRUE;
+                }
+            }
+        } while(idx != -1);
+
+        if(deleted) {
+            for(idx = 0; idx < d->creds.n_rows; idx ++) {
+                if(d->creds.rows[idx].flags & DLGROW_FLAG_DELETED) {
+                    afs_cred_delete_row(&d->creds, idx);
+                    idx--; /* we have to look at the current item again */
+                }
+            }
+
+            d->dirty = TRUE;
+            afs_dlg_update_rows(hwnd, d);
+        }
+    }
+
+    if (d->nc)
+        SendMessage(d->nc->hwnd, KHUI_WM_NC_NOTIFY, 
+                    MAKEWPARAM(0, WMNC_UPDATE_CREDTEXT), 0);
+    else if (d->config_dlg && d->dirty)
+        khui_cfg_set_flags_inst(&d->cfg, KHUI_CNFLAG_MODIFIED,
+                                KHUI_CNFLAG_MODIFIED);
+}
+
+void 
+nc_dlg_add_token(HWND hwnd) {
+    afs_dlg_data * d;
+    afs_cred_row * prow;
+    afs_cred_row trow;
+    khui_new_creds_by_type * nct;
+    wchar_t buf[256];
+    int idx;
+    size_t n;
+    size_t cb;
+    int i;
+    BOOL new_row = FALSE;
+    khm_handle ident = NULL;
+
+    d = (afs_dlg_data *)(LONG_PTR) GetWindowLongPtr(hwnd, DWLP_USER);
+
+    if (d->nc)
+        khui_cw_find_type(d->nc, afs_credtype_id, &nct);
+    else
+        nct = NULL;
+
+    if((n = SendDlgItemMessage(hwnd, IDC_NCAFS_CELL, WM_GETTEXT, 
+                               (WPARAM) ARRAYLENGTH(buf), (LPARAM) buf)) 
+       == 0)
+    {
+        /* probably should indicate that user should type something */
+        RECT r;
+        GetWindowRect(GetDlgItem(hwnd, IDC_NCAFS_CELL), &r);
+        nc_dlg_show_tooltip(hwnd, 
+                            0, 
+                            MAKEINTRESOURCE(IDS_NC_TT_NO_CELL), 
+                            MAKEINTRESOURCE(IDS_NC_TT_CANT_ADD), 
+                            2, (r.left + r.right)/ 2, r.bottom);
+        return;
+    }
+
+    if(n != wcsspn(buf, AFS_VALID_CELL_CHARS)) {
+        RECT r;
+        GetWindowRect(GetDlgItem(hwnd, IDC_NCAFS_CELL), &r);
+        nc_dlg_show_tooltip(hwnd, 
+                            0, 
+                            MAKEINTRESOURCE(IDS_NC_TT_MALFORMED_CELL), 
+                            MAKEINTRESOURCE(IDS_NC_TT_CANT_ADD), 
+                            2, (r.left + r.right)/2, r.bottom);
+        return;
+    }
+
+    /* check if this is already listed */
+    for(i=0;i<d->creds.n_rows;i++) {
+        if(!_wcsicmp(buf, d->creds.rows[i].cell))
+            break;
+    }
+
+    if(i < d->creds.n_rows) {
+        new_row = FALSE;
+
+        prow = &(d->creds.rows[i]);
+    } else {
+        new_row = TRUE;
+        prow = NULL;
+    }
+
+    ZeroMemory(&trow, sizeof(trow));
+
+    cb = (n+1) * sizeof(wchar_t);
+    trow.cell = PMALLOC(cb);
+    StringCbCopy(trow.cell, cb, buf);
+
+    /* now for the realm */
+    do {
+        idx = (int) SendDlgItemMessage(hwnd, IDC_NCAFS_REALM, 
+                                       CB_GETCURSEL, 0, 0);
+        if(idx != CB_ERR) {
+            int lp;
+            lp = (int) SendDlgItemMessage(hwnd, IDC_NCAFS_REALM, 
+                                          CB_GETITEMDATA, idx, 0);
+            if(lp != CB_ERR && lp) /* this is the 'determine realm
+                                      automatically' item */
+            {
+                trow.realm = NULL;
+                break;
+            }
+        }
+
+        if((n = SendDlgItemMessage(hwnd, IDC_NCAFS_REALM, WM_GETTEXT, 
+                                   ARRAYLENGTH(buf), (LPARAM) buf)) == 0) {
+            RECT r;
+            GetWindowRect(GetDlgItem(hwnd, IDC_NCAFS_REALM), &r);
+            nc_dlg_show_tooltip(hwnd, 
+                                0, 
+                                MAKEINTRESOURCE(IDS_NC_TT_NO_REALM), 
+                                MAKEINTRESOURCE((new_row)?
+                                                IDS_NC_TT_CANT_ADD:
+                                                IDS_NC_TT_CANT_UPDATE),
+                                2, (r.left + r.right)/2, r.bottom);
+            goto _error_exit;
+        }
+
+        if(n != wcsspn(buf, AFS_VALID_REALM_CHARS)) {
+            RECT r;
+            GetWindowRect(GetDlgItem(hwnd, IDC_NCAFS_REALM), &r);
+            nc_dlg_show_tooltip(hwnd,
+                                0, 
+                                MAKEINTRESOURCE(IDS_NC_TT_MALFORMED_REALM),
+                                MAKEINTRESOURCE((new_row)?
+                                                IDS_NC_TT_CANT_ADD:
+                                                IDS_NC_TT_CANT_UPDATE), 
+                                2, (r.left + r.right)/2, r.bottom);
+            goto _error_exit;
+        }
+
+        cb = (n+1) * sizeof(wchar_t);
+        trow.realm = PMALLOC(cb);
+        StringCbCopy(trow.realm, cb, buf);
+
+    } while(FALSE);
+
+    idx = (int)SendDlgItemMessage(hwnd, IDC_NCAFS_METHOD, 
+                                  CB_GETCURSEL, 0, 0);
+    if (idx != CB_ERR) {
+        trow.method = (afs_tk_method)
+            SendDlgItemMessage(hwnd, IDC_NCAFS_METHOD, CB_GETITEMDATA, 
+                               idx, 0);
+    } else {
+        trow.method = AFS_TOKEN_AUTO;
+    }
+
+    if (d->nc &&
+        d->nc->n_identities > 0 &&
+        d->nc->identities[0]) {
+        
+        ident = d->nc->identities[0];
+
+    } else if (d->ident) {
+
+        ident = d->ident;
+        
+    }
+
+    if(new_row) {
+        khm_boolean ok_to_add = TRUE;
+
+        if (ident) {
+            khm_handle id_conf = NULL;
+
+            ok_to_add =
+                afs_check_add_token_to_identity(trow.cell,
+                                                ident,
+                                                &id_conf);
+
+            if (!ok_to_add) {
+#if KH_VERSION_API >= 5
+                khui_alert * a;
+                wchar_t wbuf[512];
+                wchar_t wfmt[128];
+                wchar_t widname[KCDB_IDENT_MAXCCH_NAME];
+                khm_size cb;
+
+#ifdef DEBUG
+                assert(id_conf);
+#endif
+                khui_alert_create_empty(&a);
+
+                cb = sizeof(widname);
+                kcdb_identity_get_name(id_conf, widname, &cb);
+
+                LoadString(hResModule, IDS_NC_TT_CONFLICT,
+                           wfmt, ARRAYLENGTH(wfmt));
+                StringCbPrintf(wbuf, sizeof(wbuf),
+                               wfmt, trow.cell, widname);
+                khui_alert_set_message(a, wbuf);
+
+                LoadString(hResModule, IDS_NC_TT_PROBLEM,
+                           wbuf, ARRAYLENGTH(wbuf));
+                khui_alert_set_title(a, wbuf);
+
+                khui_alert_add_command(a, KHUI_PACTION_KEEP);
+                khui_alert_add_command(a, KHUI_PACTION_REMOVE);
+                khui_alert_add_command(a, KHUI_PACTION_CANCEL);
+
+                khui_alert_set_severity(a, KHERR_INFO);
+
+                khui_alert_show_modal(a);
+
+                ok_to_add = TRUE;
+
+                if (a->response == KHUI_PACTION_REMOVE) {
+                    afs_remove_token_from_identities(trow.cell);
+                } else if (a->response == KHUI_PACTION_CANCEL) {
+                    ok_to_add = FALSE;
+                }
+
+                khui_alert_release(a);
+#else
+                wchar_t widname[KCDB_IDENT_MAXCCH_NAME];
+                wchar_t wtitle[64];
+                wchar_t wmsg[512];
+                wchar_t wfmt[128];
+                khm_size cb;
+                int r;
+
+#ifdef DEBUG
+                assert(id_conf);
+#endif
+
+                cb = sizeof(widname);
+                kcdb_identity_get_name(id_conf, widname, &cb);
+                LoadString(hResModule, IDS_NC_TT_PROBLEM,
+                           wtitle, ARRAYLENGTH(wtitle));
+                LoadString(hResModule, IDS_NC_TT_CONFLICTM,
+                           wfmt, ARRAYLENGTH(wfmt));
+                StringCbPrintf(wmsg, sizeof(wmsg), wfmt,
+                               trow.cell, widname);
+                r = MessageBox(NULL, wmsg, wtitle,
+                               MB_YESNOCANCEL | MB_ICONWARNING |
+                               MB_APPLMODAL);
+
+                ok_to_add = TRUE;
+                if (r == IDNO) {
+                    afs_remove_token_from_identities(trow.cell);
+                } else if (r == IDCANCEL) {
+                    ok_to_add = FALSE;
+                }
+#endif
+
+                kcdb_identity_release(id_conf);
+            }
+
+            if (!ok_to_add)
+                goto _error_exit;
+        }
+
+        prow = afs_cred_get_new_row(&d->creds);
+    } else {
+        if (prow->cell)
+            PFREE(prow->cell);
+
+        if(prow->realm)
+            PFREE(prow->realm);
+
+        ZeroMemory(prow, sizeof(*prow));
+    }
+
+    *prow = trow;
+
+    if (ident) {
+        afs_ident_token_set ts;
+
+        ts.ident = ident;
+        ts.l = &d->creds;
+        ts.add_new = FALSE;
+        ts.update_info = FALSE;
+
+        kcdb_credset_apply(NULL, afs_get_id_creds_apply_proc,
+                           &ts);
+    }
+
+    afs_dlg_update_rows(hwnd, d);
+
+    d->dirty = TRUE;
+
+    if (d->nc)
+        SendMessage(d->nc->hwnd, KHUI_WM_NC_NOTIFY, 
+                    MAKEWPARAM(0, WMNC_UPDATE_CREDTEXT), 0);
+    else if (d->config_dlg) {
+        khui_cfg_set_flags_inst(&d->cfg,
+                                KHUI_CNFLAG_MODIFIED,
+                                KHUI_CNFLAG_MODIFIED);
+    }
+
+    return;
+
+_error_exit:
+    if(trow.realm)
+        PFREE(trow.realm);
+    if(trow.cell)
+        PFREE(trow.cell);
+}
+
+/* this is shared between the new credentials window and the AFS per
+   identity configuration dialog. */
+INT_PTR CALLBACK 
+afs_dlg_proc(HWND hwnd,
+             UINT uMsg,
+             WPARAM wParam,
+             LPARAM lParam)
+{
+    switch(uMsg) {
+    case WM_INITDIALOG:
+        {
+            HWND hw;
+            HIMAGELIST hw_ilist;
+            afs_dlg_data * d;
+            khui_new_creds_by_type * nct = NULL;
+            RECT r;
+
+            d = PMALLOC(sizeof(*d));
+            ZeroMemory(d, sizeof(*d));
+
+            InitializeCriticalSection(&d->cs);
+
+            /* lParam is a pointer to a khui_new_creds structure */
+            d->nc = (khui_new_creds *) lParam;
+
+            if (d->nc)
+                khui_cw_find_type(d->nc, afs_credtype_id, &nct);
+
+#pragma warning(push)
+#pragma warning(disable: 4244)
+            SetWindowLongPtr(hwnd, DWLP_USER, (LPARAM) d);
+#pragma warning(pop)
+
+            EnterCriticalSection(&d->cs);
+
+            if (nct)
+                nct->aux = (LPARAM) d;
+
+            /* create the tooltip window */
+            d->tooltip = 
+                CreateWindowEx(WS_EX_TOPMOST,
+                               TOOLTIPS_CLASS,
+                               NULL,
+                               WS_POPUP | TTS_BALLOON | TTS_ALWAYSTIP,
+                               CW_USEDEFAULT, CW_USEDEFAULT,
+                               CW_USEDEFAULT, CW_USEDEFAULT,
+                               hwnd,  /* make this an owned window, so
+                                         we don't have to worry about
+                                         destroying it */
+                               NULL,
+                               hInstance,
+                               NULL);
+
+            SetWindowPos(d->tooltip,
+                         HWND_TOPMOST,
+                         0,
+                         0,
+                         0,
+                         0,
+                         SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
+
+            {
+                TOOLINFO ti;
+
+                ZeroMemory(&ti, sizeof(ti));
+                ti.cbSize = sizeof(ti);
+                ti.uFlags = TTF_TRACK;
+                ti.hwnd = hwnd;
+                ti.uId = 0;
+                ti.hinst = hResModule;
+                ti.lpszText = L"";
+                GetClientRect(hwnd, &(ti.rect));
+
+                SendMessage(d->tooltip, TTM_ADDTOOL, 0, (LPARAM) &ti);
+            }
+
+            /* we only initialize the constant bits here. */
+            hw = GetDlgItem(hwnd, IDC_NCAFS_TOKENLIST);
+
+            GetClientRect(hw, &r);
+
+            /* set the list view status icons */
+            hw_ilist = ImageList_Create(GetSystemMetrics(SM_CXSMICON),
+                                        GetSystemMetrics(SM_CYSMICON),
+                                        ILC_COLOR8 | ILC_MASK,
+                                        4, 4);
+#ifdef DEBUG
+            assert(hw_ilist);
+#endif
+            {
+                HICON hi;
+
+                hi = LoadImage(hResModule, MAKEINTRESOURCE(IDI_NC_NEW),
+                               IMAGE_ICON,
+                               GetSystemMetrics(SM_CXSMICON),
+                               GetSystemMetrics(SM_CYSMICON),
+                               LR_DEFAULTCOLOR);
+
+                d->idx_new_token = ImageList_AddIcon(hw_ilist, hi) + 1;
+
+                DestroyIcon(hi);
+
+                hi = LoadImage(hResModule, MAKEINTRESOURCE(IDI_NC_EXIST),
+                               IMAGE_ICON,
+                               GetSystemMetrics(SM_CXSMICON),
+                               GetSystemMetrics(SM_CYSMICON),
+                               LR_DEFAULTCOLOR);
+                d->idx_existing_token = ImageList_AddIcon(hw_ilist, hi) + 1;
+
+                DestroyIcon(hi);
+
+                hi = LoadImage(hResModule,
+                               MAKEINTRESOURCE(IDI_NC_NOTOWNED),
+                               IMAGE_ICON,
+                               GetSystemMetrics(SM_CXSMICON),
+                               GetSystemMetrics(SM_CYSMICON),
+                               LR_DEFAULTCOLOR);
+                d->idx_bad_token = ImageList_AddIcon(hw_ilist, hi) + 1 ;
+
+                DestroyIcon(hi);
+            }
+
+            ListView_SetImageList(hw, hw_ilist, LVSIL_STATE);
+
+            ListView_DeleteAllItems(hw);
+
+            /* set the columns */
+            {
+                LVCOLUMN lc;
+                wchar_t wbuf[256];
+
+                lc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT;
+                lc.fmt = LVCFMT_LEFT;
+                lc.cx = ((r.right - r.left) * 2) / 5;
+                LoadString(hResModule, IDS_NCAFS_COL_CELL, 
+                           wbuf, ARRAYLENGTH(wbuf));
+                lc.pszText = wbuf;
+
+                ListView_InsertColumn(hw, 0, &lc);
+
+                lc.mask |= LVCF_SUBITEM;
+                //lc.cx is the same as above
+                lc.iSubItem = NCAFS_IDX_REALM;
+                LoadString(hResModule, IDS_NCAFS_COL_REALM, 
+                           wbuf, ARRAYLENGTH(wbuf));
+
+                ListView_InsertColumn(hw, 1, &lc);
+
+                lc.cx = ((r.right - r.left) * 1) / 5;
+                lc.iSubItem = NCAFS_IDX_METHOD;
+                LoadString(hResModule, IDS_NCAFS_COL_METHOD, 
+                           wbuf, ARRAYLENGTH(wbuf));
+
+                ListView_InsertColumn(hw, 2, &lc);
+            }
+
+            /* Set the items for the 'method' combo box */
+            hw = GetDlgItem(hwnd, IDC_NCAFS_METHOD);
+
+            {
+                wchar_t wbuf[KHUI_MAXCB_SHORT_DESC];
+                afs_tk_method method = -1;
+                int idx;
+
+                SendMessage(hw, CB_RESETCONTENT, 0, 0);
+
+                while((method = afs_get_next_method_id(method)) >= 0) {
+                    afs_method_describe(method, KCDB_TS_SHORT,
+                                        wbuf, sizeof(wbuf));
+                    idx = (int)SendMessage(hw, CB_INSERTSTRING,
+                                           (WPARAM) -1, (LPARAM) wbuf);
+#ifdef DEBUG
+                    assert(idx != CB_ERR);
+#endif
+                    SendMessage(hw, CB_SETITEMDATA, (WPARAM) idx,
+                                (LPARAM)  method);
+                }
+
+                /* finally, set the current selection to auto, which
+                   is the first method returned by
+                   afs_get_next_method_id() */
+                SendMessage(hw, CB_SETCURSEL, 0, 0);
+            }
+
+            d->afs_enabled = TRUE;
+            SendDlgItemMessage(hwnd, IDC_NCAFS_OBTAIN, 
+                               BM_SETCHECK, BST_CHECKED, 0);
+
+            LeaveCriticalSection(&d->cs);
+
+            /* the cells and realms combo boxes need to be filled
+               in the plugin thread since that requires making
+               potentially blocking and non-thread safe calls */
+        }
+        return TRUE;
+
+    case WM_DESTROY:
+        {
+            afs_dlg_data * d;
+            khui_new_creds_by_type * nct;
+
+            d = (afs_dlg_data *)(LONG_PTR) 
+                GetWindowLongPtr(hwnd, DWLP_USER);
+
+            EnterCriticalSection(&d->cs);
+
+            if (d->nc) {
+                khui_cw_find_type(d->nc, afs_credtype_id, &nct);
+
+                nct->aux = (LPARAM) NULL;
+            }
+
+            afs_cred_free_rows(&d->creds);
+
+            LeaveCriticalSection(&d->cs);
+            DeleteCriticalSection(&d->cs);
+
+            PFREE(d);
+        }
+        return TRUE;
+
+    case WM_COMMAND:
+        {
+            afs_dlg_data * d;
+            khui_new_creds_by_type * nct;
+
+            d = (afs_dlg_data *)(LONG_PTR) 
+                GetWindowLongPtr(hwnd, DWLP_USER);
+
+            EnterCriticalSection(&d->cs);
+
+            if (d->nc)
+                khui_cw_find_type(d->nc, afs_credtype_id, &nct);
+            else
+                nct = NULL;
+
+            nc_dlg_hide_tooltip(hwnd, 0);
+
+            /* Handle WM_COMMAND */
+            switch(wParam) {
+            case MAKEWPARAM(IDC_NCAFS_OBTAIN, BN_CLICKED):
+                {
+                    BOOL c;
+                    c = (SendDlgItemMessage(hwnd, IDC_NCAFS_OBTAIN, 
+                                            BM_GETCHECK, 0, 0) 
+                         == BST_CHECKED);
+                    d->afs_enabled = c;
+                    d->dirty = TRUE;
+                    if (d->nc)
+                        khui_cw_enable_type(d->nc, afs_credtype_id, c);
+                    else if (d->config_dlg)
+                        khui_cfg_set_flags_inst(&d->cfg,
+                                                KHUI_CNFLAG_MODIFIED,
+                                                KHUI_CNFLAG_MODIFIED);
+                    nc_dlg_enable(hwnd, c);
+                }
+                break;
+
+            case MAKEWPARAM(IDC_NCAFS_ADD_TOKEN, BN_CLICKED):
+                {
+                    nc_dlg_add_token(hwnd);
+                }
+                break;
+
+            case MAKEWPARAM(IDC_NCAFS_DELETE_TOKEN, BN_CLICKED):
+                {
+                    nc_dlg_del_token(hwnd);
+                }
+                break;
+            }
+
+            LeaveCriticalSection(&d->cs);
+        }
+        return TRUE;
+
+    case KHUI_WM_NC_NOTIFY:
+        {
+            afs_dlg_data * d;
+            khui_new_creds_by_type * nct;
+
+            d = (afs_dlg_data *)(LONG_PTR) 
+                GetWindowLongPtr(hwnd, DWLP_USER);
+
+            EnterCriticalSection(&d->cs);
+
+            if (d->nc)
+                khui_cw_find_type(d->nc, afs_credtype_id, &nct);
+            else
+                nct = NULL;
+
+            switch(HIWORD(wParam)) {
+            case WMNC_DIALOG_SETUP:
+                {
+                    SendDlgItemMessage(hwnd, IDC_NCAFS_CELL, 
+                                       CB_RESETCONTENT, 0, 0);
+                    
+                    /* load the LRU cells */
+                    {
+                        wchar_t * buf;
+                        wchar_t *s;
+                        khm_size cbbuf;
+
+                        if(khc_read_multi_string(csp_params, L"LRUCells", 
+                                                 NULL, &cbbuf) == 
+                           KHM_ERROR_TOO_LONG) {
+                            buf = PMALLOC(cbbuf);
+                            khc_read_multi_string(csp_params, L"LRUCells", 
+                                                  buf, &cbbuf);
+                            s = buf;
+                            while(*s) {
+                                SendDlgItemMessage(hwnd, IDC_NCAFS_CELL, 
+                                                   CB_ADDSTRING, 0, (LPARAM) s);
+                                s += wcslen(s) + 1;
+                            }
+                            PFREE(buf);
+                        }
+                    }
+
+                    /* now, if the root cell is not in the LRU, add it */
+                    {
+                        char buf[256];
+                        wchar_t wbuf[256];
+
+                        if(!cm_GetRootCellName(buf)) {
+                            AnsiStrToUnicode(wbuf, sizeof(wbuf), buf);
+                            if(SendDlgItemMessage(hwnd,
+                                                  IDC_NCAFS_CELL,
+                                                  CB_FINDSTRINGEXACT,
+                                                  (WPARAM) -1,
+                                                  (LPARAM) wbuf) == CB_ERR) {
+                                SendDlgItemMessage(hwnd, IDC_NCAFS_CELL, 
+                                                   CB_ADDSTRING, 
+                                                   0, (LPARAM) wbuf);
+                            }
+                            SendDlgItemMessage(hwnd, IDC_NCAFS_CELL, 
+                                               CB_SELECTSTRING, 
+                                               -1, (LPARAM) wbuf);
+                        }
+                    }
+
+                    SendDlgItemMessage(hwnd, IDC_NCAFS_REALM, 
+                                       CB_RESETCONTENT, 0, 0);
+
+                    /* as for the realms, we have a special one here */
+                    {
+                        wchar_t wbuf[256];
+                        int idx;
+
+                        LoadString(hResModule, IDS_NC_REALM_AUTO, wbuf, 
+                                   (int) ARRAYLENGTH(wbuf));
+                        idx = (int) SendDlgItemMessage(hwnd, IDC_NCAFS_REALM, 
+                                                       CB_ADDSTRING, 0, 
+                                                       (LPARAM) wbuf);
+                        /* item data for the realm strings is the
+                           answer to the question, "is this the
+                           'determine realm automatically' item?" */
+                        SendDlgItemMessage(hwnd, IDC_NCAFS_REALM, 
+                                           CB_SETITEMDATA, idx, TRUE);
+                        SendDlgItemMessage(hwnd, IDC_NCAFS_REALM, 
+                                           CB_SELECTSTRING, 
+                                           -1, (LPARAM) wbuf);
+                    }
+
+                    /* load the LRU realms */
+                    {
+                        wchar_t * buf;
+                        wchar_t *s;
+                        int idx;
+                        khm_size cbbuf;
+
+                        if(khc_read_multi_string(csp_params, L"LRURealms", 
+                                                 NULL, &cbbuf) == 
+                           KHM_ERROR_TOO_LONG) {
+                            buf = PMALLOC(cbbuf);
+                            khc_read_multi_string(csp_params, L"LRURealms", 
+                                                  buf, &cbbuf);
+                            s = buf;
+                            while(*s) {
+                                if(SendDlgItemMessage(hwnd, IDC_NCAFS_REALM, 
+                                                      CB_FINDSTRINGEXACT, -1, 
+                                                      (LPARAM) s) == CB_ERR) {
+                                    idx = 
+                                        (int)
+                                        SendDlgItemMessage(hwnd, 
+                                                           IDC_NCAFS_REALM, 
+                                                           CB_ADDSTRING, 
+                                                           0, (LPARAM) s);
+                                    SendDlgItemMessage(hwnd, IDC_NCAFS_REALM, 
+                                                       CB_SETITEMDATA, 
+                                                       idx, FALSE);
+                                }
+
+                                s += wcslen(s) + 1;
+                            }
+                            PFREE(buf);
+                        }
+                    }
+
+                    if (d->nc)
+                        khui_cw_enable_type(d->nc, afs_credtype_id, 
+                                            d->afs_enabled);
+
+                    nc_dlg_enable(hwnd, d->afs_enabled);
+
+                    afs_dlg_update_rows(hwnd, d);
+                }
+                break;
+
+            case WMNC_UPDATE_CREDTEXT:
+                {
+                    wchar_t wformat[256];
+                    wchar_t wstr[2048];
+                    khm_int32 flags;
+
+                    if(nct->credtext) {
+                        PFREE(nct->credtext);
+                        nct->credtext = NULL;
+                    }
+
+#ifdef DEBUG
+                    assert(d->nc);
+#endif
+
+                    if (d->nc->n_identities == 0 ||
+                        KHM_FAILED(kcdb_identity_get_flags(d->nc->identities[0],
+                                                           &flags)) ||
+                        !(flags & KCDB_IDENT_FLAG_VALID))
+                        /* in this case, we don't show any credential text */
+                        break;
+
+                    wstr[0] = 0;
+
+                    if(!d->afs_enabled) {
+                        LoadString(hResModule, IDS_AFS_CREDTEXT_DIS, 
+                                   wstr, ARRAYLENGTH(wstr));
+                    } else {
+                        if(d->creds.n_rows == 0) {
+                            LoadString(hResModule, IDS_AFS_CREDTEXT_0, 
+                                       wstr, ARRAYLENGTH(wstr));
+                        } else if(d->creds.n_rows == 1) {
+                            LoadString(hResModule, IDS_AFS_CREDTEXT_1, 
+                                       wformat, ARRAYLENGTH(wformat));
+                            StringCbPrintf(wstr, sizeof(wstr), wformat, 
+                                           d->creds.rows[0].cell);
+                        } else {
+                            int i;
+                            wchar_t wcells[1024];
+
+                            LoadString(hResModule, IDS_AFS_CREDTEXT_N, 
+                                       wformat, ARRAYLENGTH(wformat));
+                            wcells[0] = 0;
+                            for(i=0; i<d->creds.n_rows; i++) {
+                                if(i > 0)
+                                    StringCbCat(wcells, sizeof(wcells), 
+                                                L", ");
+                                if(FAILED(StringCbCat(wcells, 
+                                                      sizeof(wcells), 
+                                                      d->creds.rows[i].cell))) {
+                                    size_t cch;
+                                    /* looks like we overflowed */
+                                    /* add an ellipsis at the end */
+                                    StringCchLength(wcells, ARRAYLENGTH(wcells), &cch);
+                                    cch = min(ARRAYLENGTH(wcells) - 4, cch);
+                                    StringCchCopy(wcells + cch, 4, L"...");
+
+                                    break;
+                                }
+                            }
+
+                            StringCbPrintf(wstr, sizeof(wstr), wformat, wcells);
+                        }
+                    }
+
+                    if(wstr[0] != 0) {
+                        size_t cbs;
+                        StringCbLength(wstr, sizeof(wstr), &cbs);
+                        cbs += sizeof(wchar_t);
+                        assert(nct->credtext == NULL);
+                        nct->credtext = PMALLOC(cbs);
+                        StringCbCopy(nct->credtext, cbs, wstr);
+                    } else {
+                        /* something went wrong */
+                        nct->credtext = NULL;
+                    }
+                }
+                break;
+
+            case WMNC_CREDTEXT_LINK:
+                {
+                    khui_htwnd_link * l;
+                    wchar_t wid[KHUI_MAXCCH_HTLINK_FIELD];
+                    wchar_t * wids;
+
+                    l = (khui_htwnd_link *) lParam;
+
+                    StringCchCopyN(wid, ARRAYLENGTH(wid), l->id, l->id_len);
+                    wids = wcschr(wid, L':');
+                        
+                    if(!wids)
+                        break;
+                    else
+                        wids++;
+
+#ifdef DEBUG
+                    assert(d->nc);
+#endif
+
+                    if(!wcscmp(wids, L"Enable")) {
+                        SendDlgItemMessage(hwnd, IDC_NCAFS_OBTAIN, 
+                                           BM_SETCHECK, BST_CHECKED, 0);
+                        d->afs_enabled = TRUE;
+                        khui_cw_enable_type(d->nc, afs_credtype_id, TRUE);
+                        nc_dlg_enable(hwnd, TRUE);
+                    }
+                }
+                break;
+
+            case WMNC_IDENTITY_CHANGE:
+                kmq_post_sub_msg(afs_sub, KMSG_CRED, 
+                                 KMSG_CRED_DIALOG_NEW_IDENTITY, 0, 
+                                 (void *) d->nc);
+                break;
+                
+            case WMNC_AFS_UPDATE_ROWS:
+                afs_dlg_update_rows(hwnd, d);
+
+#ifdef DEBUG
+                assert(d->nc);
+#endif
+
+                PostMessage(d->nc->hwnd, KHUI_WM_NC_NOTIFY, 
+                            MAKEWPARAM(0, WMNC_UPDATE_CREDTEXT), 0);
+                break;
+            }
+
+            LeaveCriticalSection(&d->cs);
+        }
+        return TRUE;
+
+    case WM_NOTIFY:
+        if(wParam == IDC_NCAFS_TOKENLIST) {
+            LPNMHDR lpnmh = (LPNMHDR) lParam;
+
+            if(lpnmh->code == LVN_ITEMCHANGED) {
+                /* when an item in the list view is clicked, we
+                   load the corresponding values into the edit and
+                   combo boxes */
+                NMLISTVIEW *lpnmlv = (NMLISTVIEW *) lpnmh;
+                LVITEM lvi;
+                HWND hw;
+                int idx;
+                int row;
+                afs_dlg_data * d;
+
+                if (!(lpnmlv->uChanged & LVIF_STATE) ||
+                    !(lpnmlv->uNewState & LVIS_SELECTED) ||
+                    (lpnmlv->iItem == -1))
+
+                    return TRUE;
+
+                d = (afs_dlg_data *)(LONG_PTR) 
+                    GetWindowLongPtr(hwnd, DWLP_USER);
+
+                EnterCriticalSection(&d->cs);
+
+                hw = GetDlgItem(hwnd, IDC_NCAFS_TOKENLIST);
+
+                idx = lpnmlv->iItem;
+
+                ZeroMemory(&lvi, sizeof(lvi));
+                lvi.iItem = idx;
+                lvi.iSubItem = 0;
+                lvi.mask = LVIF_PARAM;
+
+                if(!ListView_GetItem(hw, &lvi))
+                    goto _done_notify_select;
+
+                /* ok, now lvi.lParam should be the row of the token */
+                row = (int) lvi.lParam;
+                if(row < 0 || row >= d->creds.n_rows)
+                    goto _done_notify_select;
+
+                SetDlgItemText(hwnd, IDC_NCAFS_CELL, 
+                               d->creds.rows[row].cell);
+                if(d->creds.rows[row].realm != NULL) {
+                    SetDlgItemText(hwnd, IDC_NCAFS_REALM, 
+                                   d->creds.rows[row].realm);
+                } else {
+                    wchar_t wbuf[256];
+                    int idx;
+                        
+                    LoadString(hResModule, IDS_NC_REALM_AUTO, wbuf, 
+                               ARRAYLENGTH(wbuf));
+                    idx = (int) SendDlgItemMessage(hwnd, IDC_NCAFS_REALM, 
+                                                   CB_FINDSTRINGEXACT, -1, 
+                                                   (LPARAM) wbuf);
+                    SendDlgItemMessage(hwnd, IDC_NCAFS_REALM, CB_SETCURSEL,
+                                       idx, 0);
+                }
+                SendDlgItemMessage(hwnd, IDC_NCAFS_METHOD, CB_SETCURSEL, 
+                                   d->creds.rows[row].method, 0);
+            _done_notify_select:
+                LeaveCriticalSection(&d->cs);
+
+            } else if (lpnmh->code == NM_DBLCLK) {
+
+                LPNMITEMACTIVATE pnmi;
+                LVITEM lvi;
+                HWND hw;
+                afs_dlg_data * d;
+                int row;
+                int x,y;
+                RECT r;
+
+                d = (afs_dlg_data *)(LONG_PTR) 
+                    GetWindowLongPtr(hwnd, DWLP_USER);
+
+                EnterCriticalSection(&d->cs);
+
+                pnmi = (LPNMITEMACTIVATE) lpnmh;
+
+                hw = GetDlgItem(hwnd, IDC_NCAFS_TOKENLIST);
+
+                ZeroMemory(&lvi, sizeof(lvi));
+                lvi.iItem = pnmi->iItem;
+                lvi.iSubItem = 0;
+                lvi.mask = LVIF_PARAM;
+
+                if (!ListView_GetItem(hw, &lvi))
+                    goto _done_notify_click;
+
+                row = (int) lvi.lParam;
+                if(row < 0 || row >= d->creds.n_rows)
+                    goto _done_notify_click;
+
+                ListView_GetItemRect(hw, pnmi->iItem, &r, LVIR_SELECTBOUNDS);
+                x = (r.left + r.right) / 2;
+                y = (r.bottom);
+
+                GetWindowRect(hw, &r);
+                y += r.top;
+                x += r.left;
+
+                if (d->creds.rows[row].flags & DLGROW_FLAG_NOTOWNED) {
+                    nc_dlg_show_tooltip(hwnd, 0,
+                                        MAKEINTRESOURCE(IDS_NC_TT_CONFLICTD),
+                                        MAKEINTRESOURCE(IDS_NC_TT_PROBLEM),
+                                        2,
+                                        x,y);
+                } else if (d->creds.rows[row].flags &
+                           DLGROW_FLAG_EXPIRED) {
+                    nc_dlg_show_tooltip(hwnd, 0,
+                                        MAKEINTRESOURCE(IDS_NC_TT_EXPIRED),
+                                        MAKEINTRESOURCE(IDS_NC_TT_DETAILS),
+                                        1,
+                                        x, y);
+                } else if (d->creds.rows[row].flags &
+                           DLGROW_FLAG_EXISTS) {
+                    nc_dlg_show_tooltip(hwnd, 0,
+                                        MAKEINTRESOURCE(IDS_NC_TT_EXISTS),
+                                        MAKEINTRESOURCE(IDS_NC_TT_DETAILS),
+                                        1, x, y);
+                } else {
+                    nc_dlg_show_tooltip(hwnd, 0,
+                                        MAKEINTRESOURCE(IDS_NC_TT_NEW),
+                                        MAKEINTRESOURCE(IDS_NC_TT_DETAILS),
+                                        1, x, y);
+                }
+
+            _done_notify_click:
+                LeaveCriticalSection(&d->cs);
+            }
+        }
+        return TRUE;
+
+    case WM_TIMER:
+        {
+            if(wParam == DLG_TOOLTIP_TIMER_ID) {
+                KillTimer(hwnd, DLG_TOOLTIP_TIMER_ID);
+                nc_dlg_hide_tooltip(hwnd, 0);
+            }
+        }
+        return TRUE;
+
+    case WM_HELP:
+        {
+            static const DWORD ctx_help[] = {
+                IDC_NCAFS_OBTAIN, IDH_OBTAIN,
+                IDC_NCAFS_CELL, IDH_CELL,
+                IDC_NCAFS_REALM, IDH_REALM,
+                IDC_NCAFS_METHOD, IDH_METHOD,
+                IDC_NCAFS_ADD_TOKEN, IDH_ADD,
+                IDC_NCAFS_DELETE_TOKEN, IDH_DELETE,
+                IDC_NCAFS_TOKENLIST, IDH_TOKENLIST,
+                0
+            };
+
+            LPHELPINFO hlp;
+
+            hlp = (LPHELPINFO) lParam;
+
+            if (hlp->iContextType != HELPINFO_WINDOW)
+                break;
+
+            afs_html_help(hlp->hItemHandle, L"::/popups_newcred.txt",
+                          HH_TP_HELP_WM_HELP, (DWORD_PTR) ctx_help);
+        }
+        return TRUE;
+    } /* switch(uMsg) */
+
+    return FALSE;
+}
+
+
+/* passed in to kcdb_credset_apply along with the afs_credset to adjust
+   newly acquired credentials to include informatino derived from the
+   new creds operation */
+khm_int32 KHMAPI 
+afs_adjust_token_ident_proc(khm_handle cred, void * vd)
+{
+    wchar_t cell[MAXCELLCHARS];
+    afs_ident_token_set * b = (afs_ident_token_set *) vd;
+    afs_cred_list * l;
+    khm_size cbbuf;
+    int i;
+
+    l = b->l;
+
+    /* ASSUMPTION: for each user, there can be tokens for only one
+       cell */
+
+    cbbuf = sizeof(cell);
+
+    if(KHM_FAILED(kcdb_cred_get_attr(cred, afs_attr_cell, NULL, cell, &cbbuf)))
+        return KHM_ERROR_SUCCESS; /* remember, kcdb doesn't care if
+                                     this run succeeded or not.  all
+                                     it wants to know if whether or
+                                     not we want to continue the
+                                     search */
+    
+    for(i=0; i<l->n_rows; i++) {
+        if((l->rows[i].flags & DLGROW_FLAG_DONE) && 
+           !_wcsicmp(cell, l->rows[i].cell)) {
+            khm_int32 method;
+
+            kcdb_cred_set_identity(cred, b->ident);
+            if(l->rows[i].realm)
+                kcdb_cred_set_attr(cred, afs_attr_realm, l->rows[i].realm, 
+                                   KCDB_CBSIZE_AUTO);
+            else
+                kcdb_cred_set_attr(cred, afs_attr_realm, NULL, 0);
+
+            method = l->rows[i].method;
+            kcdb_cred_set_attr(cred, afs_attr_method, &method, 
+                               KCDB_CBSIZE_AUTO);
+
+            break;
+        }
+    }
+
+    return KHM_ERROR_SUCCESS;
+}
+
+void
+afs_cred_write_ident_data(afs_dlg_data * d) {
+    wchar_t * lru_cell = NULL;
+    wchar_t * lru_realm = NULL;
+    wchar_t * id_cell = NULL;
+    khm_size cbidcell;
+    khm_size cbcell;
+    khm_size cbrealm;
+    khm_size cbt;
+    size_t cbz;
+    khm_handle h_idc = NULL;
+    khm_handle h_afs = NULL;
+    khm_handle h_acells = NULL;
+    khm_handle h_cellmap = NULL;
+    wchar_t idname[KCDB_IDENT_MAXCCH_NAME];
+    khm_handle ident = NULL;
+    afs_cred_list * l;
+    int i;
+
+    l = &d->creds;
+
+    if (d->nc &&
+        d->nc->n_identities > 0 &&
+        d->nc->identities[0])
+
+        ident = d->nc->identities[0];
+
+    else if (d->config_dlg)
+
+        ident = d->ident;
+
+    if (!ident)
+        return;
+
+    cbt = sizeof(idname);
+    kcdb_identity_get_name(ident, idname, &cbt);
+
+    khc_open_space(csp_afscred, L"Cells", 0, &h_cellmap);
+
+    if(ident) {
+        if(KHM_SUCCEEDED(kcdb_identity_get_config(ident,
+                                                  KHM_FLAG_CREATE,
+                                                  &h_idc))) {
+            khc_open_space(h_idc, CSNAME_AFSCRED, 
+                           KHM_FLAG_CREATE, &h_afs);
+        }
+
+        if(h_afs) {
+            khc_open_space(h_afs, L"Cells", KHM_FLAG_CREATE, 
+                           &h_acells);
+        }
+    }
+
+    if (h_afs && d) {
+        khc_write_int32(h_afs, L"AFSEnabled",
+                        !!d->afs_enabled);
+    }
+
+    if(khc_read_multi_string(csp_params, 
+                             L"LRUCells", 
+                             NULL,
+                             &cbcell) == KHM_ERROR_TOO_LONG) {
+        cbcell += MAXCELLCHARS * sizeof(wchar_t) * 
+            l->n_rows;
+        lru_cell = PMALLOC(cbcell);
+        ZeroMemory(lru_cell, cbcell);
+        cbt = cbcell;
+                    
+        khc_read_multi_string(csp_params,
+                              L"LRUCells",
+                              lru_cell,
+                              &cbt);
+    } else {
+        cbcell = MAXCELLCHARS * sizeof(wchar_t) * 
+            l->n_rows;
+        if (cbcell > 0) {
+            lru_cell = PMALLOC(cbcell);
+            ZeroMemory(lru_cell, cbcell);
+        } else {
+            lru_cell = NULL;
+        }
+    }
+
+    if(khc_read_multi_string(csp_params,
+                             L"LRURealms",
+                             NULL,
+                             &cbrealm) == KHM_ERROR_TOO_LONG) {
+        cbrealm += MAXCELLCHARS * sizeof(wchar_t) * l->n_rows;
+        lru_realm = PMALLOC(cbrealm);
+        ZeroMemory(lru_realm, cbrealm);
+        cbt = cbrealm;
+
+        khc_read_multi_string(csp_params,
+                              L"LRURealms",
+                              lru_realm,
+                              &cbt);
+    } else {
+        cbrealm = MAXCELLCHARS * sizeof(wchar_t) * l->n_rows;
+        if (cbrealm > 0) {
+            lru_realm = PMALLOC(cbrealm);
+            ZeroMemory(lru_realm, cbrealm);
+        } else {
+            lru_cell = NULL;
+        }
+    }
+
+    cbidcell = MAXCELLCHARS * sizeof(wchar_t) * l->n_rows;
+    if (cbidcell > 0) {
+        id_cell = PMALLOC(cbidcell);
+        ZeroMemory(id_cell, cbidcell);
+    } else {
+        id_cell = NULL;
+    }
+
+    for(i=0; i < l->n_rows; i++)
+        if(!(l->rows[i].flags & DLGROW_FLAG_DELETED)) {
+            khm_handle h_acell = NULL;
+            
+            if(!multi_string_find(lru_cell, 
+                                  l->rows[i].cell, 0)) {
+                cbz = cbcell;
+                multi_string_append(lru_cell, &cbz, 
+                                    l->rows[i].cell);
+            }
+
+            if(l->rows[i].realm && 
+               !multi_string_find(lru_realm, 
+                                  l->rows[i].realm, 0)) {
+                cbz = cbrealm;
+                multi_string_append(lru_realm, &cbz, 
+                                    l->rows[i].realm);
+            }
+
+            cbz = cbidcell;
+            multi_string_append(id_cell, &cbz, 
+                                l->rows[i].cell);
+
+            if(h_acells && 
+               KHM_SUCCEEDED(khc_open_space(h_acells, 
+                                            l->rows[i].cell, 
+                                            KHM_FLAG_CREATE, 
+                                            &h_acell))) {
+                wchar_t methodname[KHUI_MAXCCH_NAME];
+
+                afs_get_method_name(l->rows[i].method,
+                                    methodname,
+                                    sizeof(methodname));
+
+                khc_write_string(h_acell, L"MethodName", 
+                                 methodname);
+
+                if(l->rows[i].realm)
+                    khc_write_string(h_acell, L"Realm", 
+                                     l->rows[i].realm);
+                else
+                    khc_write_string(h_acell, L"Realm", L"");
+                khc_close_space(h_acell);
+            }
+
+            if (h_cellmap) {
+                khc_write_string(h_cellmap,
+                                 l->rows[i].cell,
+                                 idname);
+            }
+        }
+
+    if (lru_cell)                
+        khc_write_multi_string(csp_params,
+                               L"LRUCells", lru_cell);
+    if (lru_realm)
+        khc_write_multi_string(csp_params,
+                               L"LRURealms", lru_realm);
+    if (id_cell)
+        khc_write_multi_string(h_afs, L"Cells",
+                               id_cell);
+
+    if (d->config_dlg) {
+        if (d->dirty)
+            khui_cfg_set_flags_inst(&d->cfg, KHUI_CNFLAG_APPLIED,
+                                    KHUI_CNFLAG_APPLIED |
+                                    KHUI_CNFLAG_MODIFIED);
+        else
+            khui_cfg_set_flags_inst(&d->cfg, 0,
+                                    KHUI_CNFLAG_MODIFIED);
+    }
+
+    d->dirty = FALSE;
+
+    if(h_cellmap)
+        khc_close_space(h_cellmap);
+    if(h_idc)
+        khc_close_space(h_idc);
+    if(h_afs)
+        khc_close_space(h_afs);
+    if(h_acells)
+        khc_close_space(h_acells);
+    if(id_cell)
+        PFREE(id_cell);
+    if(lru_cell)
+        PFREE(lru_cell);
+    if(lru_realm)
+        PFREE(lru_realm);
+}
+
+khm_int32
+afs_msg_newcred(khm_int32 msg_subtype, 
+                khm_ui_4 uparam, 
+                void * vparam) {
+
+    switch(msg_subtype) {
+    case KMSG_CRED_NEW_CREDS:
+        {
+            khui_new_creds * nc;
+            khui_new_creds_by_type * nct;
+            wchar_t wbuf[256];
+            size_t cbsize;
+
+            nc = (khui_new_creds *) vparam;
+
+            nct = PMALLOC(sizeof(*nct));
+            ZeroMemory(nct, sizeof(*nct));
+
+            nct->type = afs_credtype_id;
+            nct->ordinal = 3;
+
+            LoadString(hResModule, IDS_AFS_NAME, wbuf, ARRAYLENGTH(wbuf));
+            StringCbLength(wbuf, sizeof(wbuf), &cbsize);
+            cbsize += sizeof(wchar_t);
+
+            nct->name = PMALLOC(cbsize);
+            StringCbCopy(nct->name, cbsize, wbuf);
+
+            nct->h_module = hResModule;
+            nct->dlg_proc = afs_dlg_proc;
+            nct->dlg_template = MAKEINTRESOURCE(IDD_NC_AFS);
+            nct->type_deps[nct->n_type_deps++] = krb5_credtype_id;
+
+            if (krb4_credtype_id < 0) {
+                kcdb_credtype_get_id(KRB4_CREDTYPE_NAME,
+                                     &krb4_credtype_id);
+            }
+            if (krb4_credtype_id >= 0) {
+                nct->type_deps[nct->n_type_deps++] =
+                    krb4_credtype_id;
+            }
+
+            khui_cw_add_type(nc, nct);
+        }
+        break;
+
+    case KMSG_CRED_RENEW_CREDS:
+        {
+            khui_new_creds * nc;
+            khui_new_creds_by_type * nct;
+
+            nc = (khui_new_creds *) vparam;
+
+            nct = PMALLOC(sizeof(*nct));
+            ZeroMemory(nct, sizeof(*nct));
+
+            nct->type = afs_credtype_id;
+            nct->type_deps[nct->n_type_deps++] = krb5_credtype_id;
+            if (krb4_credtype_id < 0) {
+                kcdb_credtype_get_id(KRB4_CREDTYPE_NAME,
+                                     &krb4_credtype_id);
+            }
+            if (krb4_credtype_id >= 0) {
+                nct->type_deps[nct->n_type_deps++] =
+                    krb4_credtype_id;
+            }
+
+            khui_cw_add_type(nc, nct);
+        }
+        break;
+
+    case KMSG_CRED_DIALOG_PRESTART:
+        {
+            khui_new_creds * nc;
+            khui_new_creds_by_type * nct = NULL;
+            HWND hwnd;
+
+            nc = (khui_new_creds *) vparam;
+            khui_cw_find_type(nc, afs_credtype_id, &nct);
+
+            if(!nct)
+                break;
+
+            hwnd = nct->hwnd_panel;
+            if (!hwnd)
+                break;
+
+            PostMessage(hwnd, KHUI_WM_NC_NOTIFY,
+                        MAKEWPARAM(0,WMNC_DIALOG_SETUP), 0);
+        }
+        break;
+
+    case KMSG_CRED_DIALOG_NEW_IDENTITY:
+        {
+            khui_new_creds * nc;
+            khui_new_creds_by_type * nct = NULL;
+            afs_dlg_data * d;
+
+            nc = (khui_new_creds *) vparam;
+            khui_cw_find_type(nc, afs_credtype_id, &nct);
+
+            if(nct == NULL)
+                break;
+
+            d = (afs_dlg_data *) nct->aux;
+
+            if(d == NULL)
+                break;
+
+            EnterCriticalSection(&d->cs);
+
+            if (nct->aux == 0) {
+                LeaveCriticalSection(&d->cs);
+                break;
+            }
+
+            /* we should load up the selected tokens for this
+               identity */
+            if(nc->n_identities == 0) {
+                LeaveCriticalSection(&d->cs);
+                /* no identities selected. nothing to do */
+                break;
+            }
+
+            afs_cred_get_identity_creds(&d->creds, nc->identities[0],
+                                        &d->afs_enabled);
+
+            LeaveCriticalSection(&d->cs);
+
+            PostMessage(nct->hwnd_panel, KHUI_WM_NC_NOTIFY,
+                        MAKEWPARAM(0, WMNC_AFS_UPDATE_ROWS), 0);
+        }
+        break;
+
+    case KMSG_CRED_PROCESS:
+        {
+            khui_new_creds * nc;
+            khui_new_creds_by_type * nct = NULL;
+            afs_cred_list tlist;
+            afs_cred_list * l;
+            int i;
+            BOOL failed = FALSE;    /* one or more cells failed */
+            BOOL succeeded = FALSE; /* one or more cells succeeded */
+            BOOL free_tlist = FALSE;
+            khm_handle ident = NULL;
+            afs_dlg_data * d = NULL;
+            BOOL get_tokens = TRUE;
+            BOOL ident_renew_triggered = TRUE;
+            khm_handle csp_afscred = NULL;
+            khm_handle csp_cells = NULL;
+
+            nc = (khui_new_creds *) vparam;
+            khui_cw_find_type(nc, afs_credtype_id, &nct);
+
+            if(!nct)
+                break;
+
+            _begin_task(0);
+            _report_cs0(KHERR_INFO,
+                        L"Getting AFS tokens...");
+            _describe();
+
+            if(nc->result != KHUI_NC_RESULT_PROCESS &&
+               nc->subtype != KMSG_CRED_RENEW_CREDS) {
+                /* nothing to do */
+                khui_cw_set_response(nc, afs_credtype_id,
+                                     KHUI_NC_RESPONSE_SUCCESS);
+
+                _report_cs0(KHERR_INFO, 
+                            L"Cancelling");
+                _end_task();
+                break;
+            }
+
+            /* we can't proceed if Kerberos 5 has failed */
+            if(!khui_cw_type_succeeded(nc, krb5_credtype_id)) {
+                khui_cw_set_response(nc, afs_credtype_id,
+                                     KHUI_NC_RESPONSE_FAILED);
+
+                _report_cs0(KHERR_INFO,
+                            L"Kerberos 5 plugin failed to process credentials request.  Aborting");
+                _end_task();
+                break;
+            }
+
+            if (nc->subtype == KMSG_CRED_RENEW_CREDS) {
+
+                if (nc->ctx.scope == KHUI_SCOPE_IDENT ||
+
+                    (nc->ctx.scope == KHUI_SCOPE_CREDTYPE &&
+                     nc->ctx.cred_type == afs_credtype_id) ||
+
+                    (nc->ctx.scope == KHUI_SCOPE_CRED &&
+                     nc->ctx.cred_type == afs_credtype_id)) {
+
+                    _report_cs1(KHERR_INFO,
+                                L"AFS Renew Creds :: ident %1!p!", 
+                                _cptr(nc->ctx.identity));
+
+                } else {
+
+                    _report_cs0(KHERR_INFO,
+                                L"Renew request not applicable to AFS");
+                    _end_task();
+                    break;
+
+                }
+
+                if (nc->ctx.identity != NULL) {
+                    ident = nc->ctx.identity;
+                } else {
+                    khui_cw_set_response(nc, afs_credtype_id,
+                                         KHUI_NC_RESPONSE_FAILED);
+
+                    _report_cs0(KHERR_INFO,
+                                L"No identity specified.  Aborting");
+                    _end_task();
+                    break;
+                }
+
+                ZeroMemory(&tlist, sizeof(tlist));
+                l = &tlist;
+                free_tlist = TRUE;
+
+                afs_cred_get_identity_creds(l, ident, NULL);
+
+                /* if the identity has any tokens associated with it
+                   that aren't persistent, we should renew those as
+                   well. */
+                afs_cred_get_context_creds(l, &nc->ctx);
+
+                if (nc->ctx.scope == KHUI_SCOPE_CREDTYPE ||
+                    nc->ctx.scope == KHUI_SCOPE_CRED) {
+
+                    ident_renew_triggered = FALSE;
+
+                }
+
+            } else {
+                _report_cs1(KHERR_INFO,
+                            L"AFS New Creds :: ident %1!p!",
+                            _cptr(nc->identities[0]));
+
+                d = (afs_dlg_data *) nct->aux;
+                if(!d) {
+                    _report_cs0(KHERR_INFO,
+                                L"No dialog data found.  Aborting");
+
+                    khui_cw_set_response(nc, afs_credtype_id,
+                                         KHUI_NC_RESPONSE_FAILED);
+                    _end_task();
+                    break;
+                }
+
+                EnterCriticalSection(&d->cs);
+
+                l = &d->creds;
+
+                ident = nc->identities[0];
+                if (!ident) {
+                    LeaveCriticalSection(&d->cs);
+
+                    _report_cs0(KHERR_INFO,
+                                L"No identity specified. Aborting");
+
+                    khui_cw_set_response(nc, afs_credtype_id,
+                                         KHUI_NC_RESPONSE_FAILED);
+
+                    _end_task();
+                    break;
+                }
+
+                get_tokens = d->afs_enabled;
+            }
+
+            if (!get_tokens)
+                goto _skip_tokens;
+
+            if (KHM_SUCCEEDED(kmm_get_plugin_config(AFS_PLUGIN_NAME, 0,
+                                                    &csp_afscred)))
+                khc_open_space(csp_afscred, L"Cells", 0, &csp_cells);
+
+            /* looks like k5 worked.  Now see about getting those
+               tokens */
+            for(i=0; i<l->n_rows; i++) {
+                int code;
+                char cell[MAXCELLCHARS];
+                char realm[MAXCELLCHARS];
+                khm_handle ctoken;
+                FILETIME ft_old;
+                FILETIME ft_new;
+                time_t new_exp = 0;
+                khm_size cb;
+                khm_int32 method = AFS_TOKEN_AUTO;
+                khm_handle csp_cell = NULL;
+
+                if (l->rows[i].flags &
+                    (DLGROW_FLAG_DONE | DLGROW_FLAG_DELETED))
+
+                    continue;
+
+                ZeroMemory(cell, sizeof(cell));
+                ZeroMemory(realm, sizeof(realm));
+
+                UnicodeStrToAnsi(cell, sizeof(cell), l->rows[i].cell);
+                if (l->rows[i].realm != NULL)
+                    UnicodeStrToAnsi(realm, sizeof(realm), 
+                                     l->rows[i].realm);
+
+                ZeroMemory(&ft_old, sizeof(ft_old));
+
+                if (!ident_renew_triggered &&
+                    (ctoken = afs_find_token(NULL, l->rows[i].cell))) {
+
+                    cb = sizeof(ft_old);
+                    kcdb_cred_get_attr(ctoken, KCDB_ATTR_EXPIRE,
+                                       NULL, &ft_old, &cb);
+
+                    kcdb_cred_release(ctoken);
+                }
+
+                if (l->rows[i].method == AFS_TOKEN_AUTO && csp_cells &&
+                    KHM_SUCCEEDED(khc_open_space(csp_cells,
+                                                 l->rows[i].cell, 0,
+                                                 &csp_cell))) {
+
+                    if (KHM_FAILED(khc_read_int32(csp_cell, L"Method", &method))) {
+                        method = l->rows[i].method;
+                    } else {
+                        _report_cs3(KHERR_INFO,
+                                    L"Overriding method %1!d! with global default %2!d! for cell %3!s!",
+                                    _int32(l->rows[i].method),
+                                    _int32(method),
+                                    _cstr(l->rows[i].cell));
+                        _resolve();
+                    }
+
+                    khc_close_space(csp_cell);               
+                } else {
+                    method = l->rows[i].method;
+                }
+
+                _report_cs3(KHERR_INFO,
+                            L"Getting tokens for cell %1!S! with realm %2!S! using method %3!d!",
+                            _cstr(cell),
+                            _cstr(realm),
+                            _int32(method));
+                _resolve();
+
+                /* make the call */
+                code = afs_klog(ident, "", cell, realm, 0, 
+                                method, &new_exp);
+
+                _report_cs1(KHERR_INFO,
+                            L"klog returns code %1!d!",
+                            _int32(code));
+
+                if(code) {
+                    failed = TRUE;
+                    l->rows[i].flags &= ~DLGROW_FLAG_DONE;
+
+                    if (!kherr_is_error()) {
+                        /* failed to get tokens, but no error was reported */
+                        _report_sr1(KHERR_ERROR, IDS_ERR_GENERAL,
+                                    _cptr(cell));
+                        _resolve();
+                    }
+
+                } else {
+                    l->rows[i].flags |= DLGROW_FLAG_DONE;
+                    succeeded = TRUE;
+
+                    if (new_exp &&
+                        !ident_renew_triggered) {
+                        TimetToFileTime(new_exp, &ft_new);
+
+                        if (CompareFileTime(&ft_old, &ft_new) >= 0) {
+                            /* getting a new token didn't improve the
+                               situation much.  We only get here if we
+                               were trying to renew tokens. So we try
+                               to trigger an identity renewal.  Doing
+                               so should get us new initial tickets
+                               which will allow us to get a better
+                               token. */
+
+                            khui_action_context ctx;
+
+                            _reportf(L"Renewal of AFS tokens for cell %s failed to get a longer token.  Triggering identity renewal", l->rows[i].cell);
+
+                            khui_context_create(&ctx,
+                                                KHUI_SCOPE_IDENT,
+                                                nc->ctx.identity,
+                                                KCDB_CREDTYPE_INVALID,
+                                                NULL);
+                            khui_action_trigger(KHUI_ACTION_RENEW_CRED,
+                                                &ctx);
+
+                            khui_context_release(&ctx);
+
+                            ident_renew_triggered = TRUE;
+                        }
+                    }
+                }
+            }
+
+        _skip_tokens:
+
+            if(failed) {
+                /* we should indicate errors if anything went wrong */
+                khui_cw_set_response(nc, afs_credtype_id, 
+                                     KHUI_NC_RESPONSE_FAILED);
+            } else {
+                khui_cw_set_response(nc, afs_credtype_id,
+                                     KHUI_NC_RESPONSE_SUCCESS);
+            }
+
+            if (succeeded && nc->subtype == KMSG_CRED_RENEW_CREDS) {
+                afs_ident_token_set b;
+
+                afs_list_tokens_internal();
+
+                /* the tokens that we just acquired need adjusting to
+                   include the realm, method and identity information
+                   derived from the new creds operation.  this is done
+                   in afs_adjust_token_ident_proc */
+                b.ident = ident;
+                b.l = l;
+                b.add_new = FALSE;
+                b.update_info = FALSE;
+
+                kcdb_credset_apply(afs_credset, afs_adjust_token_ident_proc, 
+                                   (void *) &b);
+
+                kcdb_credset_collect(NULL, afs_credset, NULL, 
+                                     afs_credtype_id, NULL);
+
+            } else if (nc->subtype == KMSG_CRED_NEW_CREDS) {
+                afs_ident_token_set b;
+
+                afs_list_tokens_internal();
+
+                /* the tokens that we just acquired need adjusting to
+                   include the realm, method and identity information
+                   derived from the new creds operation.  this is done
+                   in afs_adjust_token_ident_proc */
+                b.ident = ident;
+                b.l = l;
+                b.add_new = FALSE;
+                b.update_info = FALSE;
+
+                kcdb_credset_apply(afs_credset, afs_adjust_token_ident_proc, 
+                                   (void *) &b);
+
+                kcdb_credset_collect(NULL, afs_credset, NULL, 
+                                     afs_credtype_id, NULL);
+
+                afs_cred_write_ident_data(d);
+            }
+
+            if (d)
+                LeaveCriticalSection(&d->cs);
+
+            if (free_tlist) {
+                afs_cred_free_rows(&tlist);
+            }
+
+            if (csp_afscred)
+                khc_close_space(csp_afscred);
+
+            if (csp_cells)
+                khc_close_space(csp_cells);
+
+            _end_task();
+        }
+        break;
+
+    case KMSG_CRED_END:
+        {
+            khui_new_creds * nc;
+            khui_new_creds_by_type * nct;
+
+            nc = (khui_new_creds *) vparam;
+            khui_cw_find_type(nc, afs_credtype_id, &nct);
+
+            if(!nct)
+                break;
+
+            khui_cw_del_type(nc, afs_credtype_id);
+    
+            if (nct->name)
+                PFREE(nct->name);
+            if (nct->credtext)
+                PFREE(nct->credtext);
+
+            PFREE(nct);
+        }
+        break;
+    }
+
+    return KHM_ERROR_SUCCESS;
+}
diff --git a/src/WINNT/netidmgr_plugin/afsnewcreds.h b/src/WINNT/netidmgr_plugin/afsnewcreds.h
new file mode 100644 (file)
index 0000000..cc760cd
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2004 Massachusetts Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* $Id$ */
+
+#ifndef __AFS_NEWCREDS_H
+#define __AFS_NEWCREDS_H
+
+typedef struct tag_afs_cred_row {
+    wchar_t * cell;
+    wchar_t * realm;
+    afs_tk_method method;
+    khm_int32 flags;
+} afs_cred_row;
+
+/* we checked whether this cell exists */
+#define DLGROW_FLAG_CHECKED  0x00000001
+
+/* cell was checked and was found to be valid */
+#define DLGROW_FLAG_VALID    0x00000002
+
+/* cell was deleted  */
+#define DLGROW_FLAG_DELETED  0x00000004
+
+/* tokens obtained for cell */
+#define DLGROW_FLAG_DONE     0x00000008
+
+/* tokens for this cell already exist */
+#define DLGROW_FLAG_EXISTS   0x00000010
+
+/* tokens for this cell exist and is listed under a different
+   identity */
+#define DLGROW_FLAG_NOTOWNED 0x00000020
+
+/* tokens for this cell exist and are expired */
+#define DLGROW_FLAG_EXPIRED  0x00000040
+
+/* the subitem indexes for each data field */
+enum afs_ncwnd_subitems {
+    NCAFS_IDX_CELL=0,
+    NCAFS_IDX_REALM,
+    NCAFS_IDX_METHOD
+};
+
+#define DLG_TOOLTIP_TIMER_ID 1
+#define DLG_TOOLTIP_TIMEOUT  5000
+
+typedef struct tag_afs_cred_list {
+    afs_cred_row * rows;
+    int n_rows;
+    int nc_rows;
+} afs_cred_list;
+
+typedef struct tag_afs_dlg_data {
+    khui_new_creds * nc;
+
+    afs_cred_list creds;
+
+    khm_int32 afs_enabled;
+
+    BOOL tooltip_visible;
+    BOOL dirty;
+    HWND tooltip;
+
+    /* list view state image indices */
+    int idx_new_token;
+    int idx_existing_token;
+    int idx_bad_token;
+
+    CRITICAL_SECTION cs;
+
+    /* used with configuration dialogs */
+    khm_boolean config_dlg;
+    khui_config_init_data cfg;
+    khm_handle ident;
+} afs_dlg_data;
+
+#define AFS_DLG_ROW_ALLOC 4
+
+INT_PTR CALLBACK 
+afs_dlg_proc(HWND hwnd,
+             UINT uMsg,
+             WPARAM wParam,
+             LPARAM lParam);
+
+void 
+afs_dlg_update_rows(HWND hwnd, afs_dlg_data * d);
+
+void 
+afs_cred_flush_rows(afs_cred_list * l);
+
+void 
+afs_cred_free_rows(afs_cred_list * l);
+
+void 
+afs_cred_assert_rows(afs_cred_list * l, int n);
+
+void 
+afs_cred_delete_row(afs_cred_list * l, int i);
+
+afs_cred_row * 
+afs_cred_get_new_row(afs_cred_list * l);
+
+khm_int32 KHMAPI
+afs_cred_add_cred_proc(khm_handle cred, void * rock);
+
+void
+afs_cred_get_context_creds(afs_cred_list *l,
+                           khui_action_context * ctx);
+
+void 
+afs_cred_get_identity_creds(afs_cred_list * l, 
+                            khm_handle ident,
+                            khm_boolean * enabled);
+
+void
+afs_cred_write_ident_data(afs_dlg_data * d);
+
+khm_int32
+afs_msg_newcred(khm_int32 msg_subtype, 
+                khm_ui_4 uparam, 
+                void * vparam);
+
+#endif
diff --git a/src/WINNT/netidmgr_plugin/afsp_version.h b/src/WINNT/netidmgr_plugin/afsp_version.h
new file mode 100644 (file)
index 0000000..11974bf
--- /dev/null
@@ -0,0 +1,37 @@
+/* Copyright (c) 2004 Massachusetts Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef __AFSPLUGIN_VERSION_H
+#define __AFSPLUGIN_VERSION_H
+
+#define AFSPLUGIN_VERSION_MAJOR 1
+#define AFSPLUGIN_VERSION_MINOR 5
+#define AFSPLUGIN_VERSION_PATCH 0002
+#define AFSPLUGIN_VERSION_AUX   0
+
+#define AFSPLUGIN_VERSION       1.5.0002.0
+#define AFSPLUGIN_VERSION_STR   "1.5.0002.0"
+#define AFSPLUGIN_VERSION_LST   1,5,0002,0
+
+#endif
diff --git a/src/WINNT/netidmgr_plugin/afsp_version.h.in b/src/WINNT/netidmgr_plugin/afsp_version.h.in
new file mode 100644 (file)
index 0000000..a15043e
--- /dev/null
@@ -0,0 +1,40 @@
+afsp_version.h: NTMakefile afsp_version.h.in
+        $(COPY) << $@
+/* Copyright (c) 2004 Massachusetts Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef __AFSPLUGIN_VERSION_H
+#define __AFSPLUGIN_VERSION_H
+
+#define AFSPLUGIN_VERSION_MAJOR $(AFSPLUGIN_VERSION_MAJOR)
+#define AFSPLUGIN_VERSION_MINOR $(AFSPLUGIN_VERSION_MINOR)
+#define AFSPLUGIN_VERSION_PATCH $(AFSPLUGIN_VERSION_PATCH)
+#define AFSPLUGIN_VERSION_AUX   $(AFSPLUGIN_VERSION_AUX)
+
+#define AFSPLUGIN_VERSION       $(AFSPLUGIN_VERSION)
+#define AFSPLUGIN_VERSION_STR   "$(AFSPLUGIN_VERSION)"
+#define AFSPLUGIN_VERSION_LST   $(AFSPLUGIN_VERLIST)
+
+#endif
+<<
diff --git a/src/WINNT/netidmgr_plugin/afspext.h b/src/WINNT/netidmgr_plugin/afspext.h
new file mode 100644 (file)
index 0000000..cfe802b
--- /dev/null
@@ -0,0 +1,328 @@
+/*
+ * Copyright (c) 2004 Massachusetts Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* $Id$ */
+
+#ifndef __AFSPLUGIN_EXT_H
+#define __AFSPLUGIN_EXT_H
+
+/*! \defgroup afs_ext OpenAFS Plugin extensions 
+
+    This section documents messages and data structures used by AFS
+    extension plugins.  These are plugins which augment the behavior
+    of the AFS plugin.
+
+    When performing specific tasks for NetIDMgr, the AFS plugin will
+    send out messages to the extension plugins either via broadcast or
+    unicast.  The extension plugins provide functionality by
+    responding to these messages.
+
+  @{*/
+
+#define MAXCELLCHARS   64
+#define MAXHOSTCHARS   64
+#define MAXHOSTSPERCELL 8
+
+#define TRANSARCAFSDAEMON "TransarcAFSDaemon"
+
+#define AFS_TOKENNAME_AUTO L"Auto"
+#define AFS_TOKENNAME_KRB5 L"Kerberos5"
+#define AFS_TOKENNAME_KRB524 L"Kerberos524"
+#define AFS_TOKENNAME_KRB4 L"Kerberos4"
+
+/*! \brief An AFS token acquisition method identifier 
+
+    This takes on a value from ::afs_token_method or a token
+    acquisition method identifier assigned to an extension plugin.
+*/
+typedef khm_int32 afs_tk_method;
+
+/*! \brief Predefined token acquisition methods */
+enum afs_token_method {
+    AFS_TOKEN_AUTO = 0,         /*!< Automatic.  This method iterates
+                                  through Krb5, Krb524, Krb4 and then
+                                  any extensions which provide token
+                                  acquisition methods until one of
+                                  them succeeds. */
+    AFS_TOKEN_KRB5,             /*!< Kerberos 5 */
+    AFS_TOKEN_KRB524,           /*!< Kerberos 5 with krb524 translation */
+    AFS_TOKEN_KRB4,             /*!< Kerberos 4 */
+};
+
+/*! \brief Version of the OpenAFS Plugin
+
+    This is an internal number that identifies the version of the
+    OpenAFS plugin API that this extension was built against.  This
+    number is specified when sending the ::AFS_MSG_ANNOUNCE message.
+ */
+#define AFS_PLUGIN_VERSION 0x0000001
+
+/*! \name Messages
+
+    The AFS plugin registers the message type named ::AFS_MSG_TYPENAME
+    and sends messages of this type to notify any AFS extension
+    plugins to notify them of various events.
+
+ @{*/
+
+/*! \brief Name of the AFS plugin message
+
+    This message type is registered when the AFS plugin starts and is
+    unregistered when the plugin stops.
+
+    Use kmq_find_type() to find the type ID of this message type.
+ */
+#define AFS_MSG_TYPENAME L"AfsExtMessage"
+
+/*! \brief Announce an extension plugin
+
+    Sent by an extension plugin to announce its existence to the AFS
+    plugin.  This message should be sent by the extension plugin when
+    it has finished loading, and is the only message permitted to be
+    sent by an extension. All other messages are sent by the AFS
+    plugin.
+
+    Since this message contains pointer parameters and there is no
+    cleanup performed on this, the message should be sent using
+    kmq_send_message().
+
+    <table>
+    <tr><td>Type</td><td>type ID of ::AFS_MSG_TYPENAME</td></tr>
+    <tr><td>Subtype</td><td>::AFS_MSG_ANNOUNCE</td></tr>
+    <tr><td>uparam</td><td>0</td></tr>
+    <tr><td>vparam</td><td>Pointer to a ::afs_msg_announce structure</td></tr>
+    </table>
+
+    \note This message is only sent from extension plugins to the AFS plugin.
+ */
+#define AFS_MSG_ANNOUNCE 1
+
+/*! \brief Parameter structure for announcing an extension plugin
+
+    \see ::AFS_MSG_ANNOUNCE
+ */
+typedef struct tag_afs_msg_announce_v1 {
+    khm_size  cbsize;           /*!< Size of the strucutre.  Set to \a
+                                  sizeof(::afs_msg_announce).  If
+                                  there is a version skew between the
+                                  AFS plugin and the extension, then
+                                  this parameter will ensure that the
+                                  AFS plugin understands the correct
+                                  version of the structure. */
+
+    khm_ui_4  version;          /*!< Version of the AFS plugin that
+                                  the extension is compiled for.  Set
+                                  this to ::AFS_PLUGIN_VERSION.
+                                  Depending on this value, the AFS
+                                  plugin will either reject the
+                                  extension or determine which set of
+                                  messages and structures should be
+                                  used to communicate with the
+                                  extension. */
+
+    const wchar_t * name;       /*!< Name of the extension.  Should be
+                                  unique among all AFS extension
+                                  plugins. Size constrained by
+                                  ::KHUI_MAXCCH_NAME*/
+
+    khm_handle sub;             /*!< A valid subscription for unicast
+                                  messages.  This must have been
+                                  created through
+                                  kmq_create_subscription().  The
+                                  supplied handle will be
+                                  automatically released when the
+                                  plugin exits.  However, if the
+                                  announcement message fails, then the
+                                  extension has to release the handle
+                                  itself. */
+
+    khm_boolean provide_token_acq; /*!< non-zero if the extension
+                                     provides a token acquisition
+                                     method. The \a token_acq
+                                     substructure should be filled if
+                                     this member is set to
+                                     non-zero. */
+
+    struct {
+        const wchar_t * short_desc; /*!< Short description of token
+                                  acquisition method. (localized,
+                                  required).  Size is constrained by
+                                  ::KHUI_MAXCCH_SHORT_DESC */
+
+        const wchar_t * long_desc; /*!< Long description.  (localized,
+                                  optional).  Size is constrained by
+                                  ::KHUI_MAXCCH_LONG_DESC */
+
+        afs_tk_method method_id; /*!< Once the message is processed,
+                                  this will receive a new method
+                                  identifier.  The value of this field
+                                  on entry is ignored. */
+
+    } token_acq;                /*!< Registration information for
+                                  token acquisition method.  Only
+                                  assumed to be valid if \a
+                                  provide_token_acq is TRUE. */
+
+} afs_msg_announce;
+
+/*! \brief Sent to all extensions to resolve the identity of a token
+
+    If the identity and credentials acquisition method of an AFS token
+    cannot be determined by the AFS plugin, this message is sent out
+    to extension plugins to allow them a chance to resolve it.
+
+    If the extension plugin successfully resolves the identity and
+    token acquisition method of the specified token, it should return
+    ::KHM_ERROR_SUCCESS.  Otherwise it should return a failure code.
+    The actual return code is not interpreted other than whether or
+    not it passes the ::KHM_SUCCEEDED() test.
+
+    <table>
+    <tr><td>Type</td><td>type ID of ::AFS_MSG_TYPENAME</td></tr>
+    <tr><td>Subtype</td><td>::AFS_MSG_RESOLVE_TOKEN</td></tr>
+    <tr><td>uparam</td><td>0</td></tr>
+    <tr><td>vparam</td><td>Pointer to a ::afs_msg_resolve_token structure</td></tr>
+    </table>
+
+    \note This message is only sent from the AFS plugin to extension plugins
+
+    \note Only sent if the extension plugin has ::provide_token_acq set.
+ */
+#define AFS_MSG_RESOLVE_TOKEN 2
+
+/*! \brief Message structure for AFS_MSG_RESOLVE_TOKEN
+
+    Other than the fields marked as \a [OUT], all other fields should
+    be considered read-only and should not be modified.
+
+    \see ::AFS_MSG_RESOLVE_TOKEN
+ */
+typedef struct tag_afs_msg_resolve_token_v1 {
+    khm_size cbsize;            /*!< Size of the structure.  This will
+                                  be set to \a
+                                  sizeof(::afs_msg_resolve_token). */
+
+    const wchar_t * cell;       /*!< Specifies the cell that the token
+                                  belongs to. */
+
+    const struct ktc_token * token; /*!< The token */
+    const struct ktc_principal * serverp; /*!< Server principal */
+    const struct ktc_principal * clientp; /*!< Client principal */
+
+    khm_handle ident;           /*!< [OUT] If the extension
+                                  successfully resolves the identity,
+                                  then it should assign a handle to
+                                  the identity to this field and
+                                  return ::KHM_ERROR_SUCCESS.  The
+                                  handle will be automatically freed
+                                  by the AFS plugin. */
+
+    afs_tk_method method;       /*!< [OUT] If the extension
+                                  successfully resolves the identity,
+                                  it should also assign the token
+                                  acquisition method identifier to
+                                  this field.  The default method is
+                                  ::AFS_TOKEN_AUTO.  This field
+                                  indicates the token acquisition
+                                  method that was used to obtain the
+                                  token and is used when the token
+                                  needs to be renewed. */
+} afs_msg_resolve_token;
+
+/*! \brief Sent to an extension plugin to obtain AFS tokens
+
+    <table>
+    <tr><td>Type</td><td>type ID of ::AFS_MSG_TYPENAME</td></tr>
+    <tr><td>Subtype</td><td>::AFS_MSG_KLOG</td></tr>
+    <tr><td>uparam</td><td>0</td></tr>
+    <tr><td>vparam</td><td>Pointer to a ::afs_msg_klog</td></tr>
+    </table>
+
+    \note Only sent from the AFS plugin to extension plugins
+    \note Only sent to extension plugins which have ::provide_token_acq set.
+*/
+#define AFS_MSG_KLOG 3
+
+/*! \brief Cell configuration information
+
+    \see ::afs_msg_klog
+
+    \note This structure uses ANSI char fields instead of unicode fields.
+ */
+typedef struct tag_afs_conf_cellA_v1 {
+    khm_size cbsize;            /*!< set to \a sizeof(afs_conf_cell) */
+
+    char     name[MAXCELLCHARS]; /*!< Name of the cell */
+    short    numServers;        /*!< Number of servers for cell.
+                                  Upper bound of MAXHOSTSPERCELL */
+    short    flags;             /*!< Not used. Set to zero. */
+    struct sockaddr_in hostAddr[MAXHOSTSPERCELL];
+                                /*!< addresses for each server.  There
+                                  are \a numServers entries.*/
+    char     hostName[MAXHOSTSPERCELL][MAXHOSTCHARS];
+                                /*!< names of the servers. There are
+                                  \a numServers entries. */
+    char *   linkedCell;        /*!< Not used.  Set to zero. */
+} afs_conf_cell;
+
+/*! \brief Message parameters for AFS_MSG_KLOG message
+
+    \see ::AFS_MSG_KLOG
+
+    \note This structure uses ANSI char fields instead of unicode fields.
+ */
+typedef struct tag_afs_msg_klogA_v1 {
+    khm_size        cbsize;     /*!< Set to \a sizeof(afs_msg_klog) */
+
+    khm_handle      identity;   /*!< Handle to identity for which we
+                                  are obtaining tokens. */
+
+    const char *    service;    /*!< Service name to use when
+                                  obtaining token.  This can be NULL
+                                  if the service name has not be
+                                  determined. */
+
+    const char *    cell;       /*!< Name of cell to obtain tokens
+                                  for.  Can be NULL if the local cell
+                                  is to be used. */
+
+    const char *    realm;      /*!< Realm to use when obtaining
+                                  tokens.  Can be NULL if the realm
+                                  has not been determined. */
+
+    const afs_conf_cell * cell_config; /*!< Cell configuration for the
+                                   cell specified in \a cell. */
+
+    khm_int32       lifetime;   /*!< Advisory lifetime specifier, in
+                                  seconds.  If set to zero, means
+                                  there is no specification for
+                                  lifetime.  Extensions should feel
+                                  free to ignore this parameter. */
+} afs_msg_klog;
+
+/*!@}*/
+
+/*!@}*/
+
+#endif
diff --git a/src/WINNT/netidmgr_plugin/afsplugin.c b/src/WINNT/netidmgr_plugin/afsplugin.c
new file mode 100644 (file)
index 0000000..3dd47e1
--- /dev/null
@@ -0,0 +1,642 @@
+/*
+ * Copyright (c) 2004 Massachusetts Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* $Id$ */
+
+#include<afscred.h>
+#include<kcreddb.h>
+#include<khmsgtypes.h>
+#include<kherror.h>
+#include<khuidefs.h>
+#include<commctrl.h>
+#include<assert.h>
+
+static BOOL initialized = FALSE;
+khm_int32 afs_credtype_id = -1;
+khm_int32 krb5_credtype_id = -1;
+khm_int32 krb4_credtype_id = -1;
+khm_int32 afs_msg_type_id = -1;
+khm_int32 afs_type_principal = -1;
+khm_int32 afs_type_method = -1;
+khm_int32 afs_attr_client_princ = -1;
+khm_int32 afs_attr_server_princ = -1;
+khm_int32 afs_attr_cell = -1;
+khm_int32 afs_attr_method = -1;
+khm_int32 afs_attr_realm = -1;
+khm_handle afs_credset = NULL;
+khm_handle afs_sub = NULL;      /* AFS message subscription */
+
+/* forward dcls */
+khm_int32 KHMAPI 
+afs_msg_system(khm_int32 msg_subtype, khm_ui_4 uparam, void * vparam);
+
+khm_int32 KHMAPI 
+afs_msg_kcdb(khm_int32 msg_subtype, khm_ui_4 uparam, void * vparam);
+
+khm_int32 KHMAPI 
+afs_msg_cred(khm_int32 msg_subtype, khm_ui_4 uparam, void * vparam);
+
+khm_int32 KHMAPI 
+afs_msg_ext(khm_int32 msg_subtype, khm_ui_4 uparam, void * vparam);
+
+/* AFS plugin callback */
+khm_int32 KHMAPI 
+afs_plugin_cb(khm_int32 msg_type,
+              khm_int32 msg_subtype,
+              khm_ui_4 uparam,
+              void * vparam)
+{
+    if (msg_type == KMSG_SYSTEM)
+        return afs_msg_system(msg_subtype, uparam, vparam);
+    if (msg_type == KMSG_KCDB)
+        return afs_msg_kcdb(msg_subtype, uparam, vparam);
+    if (msg_type == KMSG_CRED)
+        return afs_msg_cred(msg_subtype, uparam, vparam);
+    if (msg_type == afs_msg_type_id)
+        return afs_msg_ext(msg_subtype, uparam, vparam);
+
+    return KHM_ERROR_SUCCESS;
+}
+
+/* ktc_principal attribute type */
+/* String */
+
+khm_int32 KHMAPI 
+afs_type_principal_toString(const void * d, 
+                            khm_size cbd, 
+                            wchar_t * buffer, 
+                            khm_size * cb_buf, 
+                            khm_int32 flags)
+{
+    size_t cbsize;
+    struct ktc_principal * p;
+    wchar_t sprinc[512] = L"";
+
+    if(!cb_buf)
+        return KHM_ERROR_INVALID_PARAM;
+
+    p = (struct ktc_principal *) d;
+
+    // assume this works.
+    afs_princ_to_string(p, sprinc, sizeof(sprinc));
+    StringCbLength(sprinc, sizeof(sprinc), &cbsize);
+    cbsize += sizeof(wchar_t);
+
+    if(!buffer || *cb_buf < cbsize) {
+        *cb_buf = cbsize;
+        return KHM_ERROR_TOO_LONG;
+    }
+
+    StringCbCopy(buffer, *cb_buf, sprinc);
+
+    *cb_buf = cbsize;
+
+    return KHM_ERROR_SUCCESS;
+}
+
+khm_boolean KHMAPI 
+afs_type_principal_isValid(const void * d,
+                           khm_size cbd)
+{
+    /*TODO: check for more inconsistencies */
+    if(cbd != sizeof(struct ktc_principal))
+        return FALSE;
+    return TRUE;
+}
+
+khm_int32 KHMAPI 
+afs_type_principal_comp(const void * d1,
+                        khm_size cbd1,
+                        const void * d2,
+                        khm_size cbd2)
+{
+    struct ktc_principal * p1 = (struct ktc_principal *) d1;
+    struct ktc_principal * p2 = (struct ktc_principal *) d2;
+    int r;
+
+    r = strcmp(p1->name, p2->name);
+    if(r != 0)
+        return r;
+    r = strcmp(p1->instance, p2->instance);
+    if(r != 0)
+        return r;
+    r = strcmp(p1->cell, p2->cell);
+    return r;
+}
+
+khm_int32 KHMAPI 
+afs_type_principal_dup(const void * d_src,
+                       khm_size cbd_src,
+                       void * d_dst,
+                       khm_size * cbd_dst)
+{
+    if(!d_dst || *cbd_dst < sizeof(struct ktc_principal)) {
+        *cbd_dst = sizeof(struct ktc_principal);
+        return KHM_ERROR_TOO_LONG;
+    }
+
+    memcpy(d_dst, d_src, sizeof(struct ktc_principal));
+    *cbd_dst = sizeof(struct ktc_principal);
+
+    return KHM_ERROR_SUCCESS;
+}
+
+khm_int32 KHMAPI
+afs_type_method_toString(const void * data,
+                         khm_size     cb_data,
+                         wchar_t *    s_buf,
+                         khm_size *   pcb_s_buf,
+                         khm_int32    flags) {
+    khm_int32 * pmethod = (khm_int32 *) data;
+    wchar_t wbuf[KHUI_MAXCCH_LONG_DESC];
+    khm_size cb;
+
+    if (!data || cb_data != sizeof(khm_int32))
+        return KHM_ERROR_INVALID_PARAM;
+
+    wbuf[0] = L'\0';
+    if (!afs_method_describe(*pmethod, flags, wbuf, sizeof(wbuf))) {
+        LoadString(hResModule,
+                   IDS_NC_METHOD_INVALID,
+                   wbuf,
+                   ARRAYLENGTH(wbuf));
+    }
+
+    StringCbLength(wbuf, sizeof(wbuf), &cb);
+    cb += sizeof(wchar_t);
+
+    if (!s_buf || *pcb_s_buf < cb) {
+        *pcb_s_buf = cb;
+        return KHM_ERROR_TOO_LONG;
+    } else {
+        StringCbCopy(s_buf, *pcb_s_buf, wbuf);
+        *pcb_s_buf = cb;
+        return KHM_ERROR_SUCCESS;
+    }
+}
+
+/* process KMSG_SYSTEM messages */
+khm_int32 KHMAPI 
+afs_msg_system(khm_int32 msg_subtype, 
+               khm_ui_4 uparam, 
+               void * vparam)
+{
+    khm_int32 rv = KHM_ERROR_UNKNOWN;
+
+    switch(msg_subtype) {
+    case KMSG_SYSTEM_INIT:
+        /* Perform critical registrations and data structure
+           initalization */
+        {
+            kcdb_credtype ct;
+            wchar_t buf[KCDB_MAXCCH_LONG_DESC];
+            size_t cbsize;
+            kcdb_attrib att;
+            khm_handle csp_afscred = NULL;
+            khm_int32 disable_afscreds = FALSE;
+
+            ZeroMemory(&ct, sizeof(ct));
+            /* first of all, register the AFS token credential type */
+            ct.id = KCDB_CREDTYPE_AUTO;
+            ct.name = AFS_CREDTYPE_NAME;
+
+            if(LoadString(hResModule, 
+                          IDS_AFS_SHORT_DESC, 
+                          buf, 
+                          ARRAYLENGTH(buf)) != 0) {
+                StringCbLength(buf, sizeof(buf), &cbsize);
+                cbsize += sizeof(wchar_t);
+                ct.short_desc = PMALLOC(cbsize);
+                StringCbCopy(ct.short_desc, cbsize, buf);
+            } else
+                ct.short_desc = NULL;
+
+            if(LoadString(hResModule, 
+                          IDS_AFS_LONG_DESC, 
+                          buf, 
+                          ARRAYLENGTH(buf)) != 0) {
+                StringCbLength(buf, sizeof(buf), &cbsize);
+                cbsize += sizeof(wchar_t);
+                ct.long_desc = PMALLOC(cbsize);
+                StringCbCopy(ct.long_desc, cbsize, buf);
+            } else
+                ct.long_desc = NULL;
+
+            ct.icon = LoadImage(hResModule, 
+                                MAKEINTRESOURCE(IDI_AFSTOKEN), 
+                                IMAGE_ICON, 
+                                0, 0, LR_DEFAULTSIZE);
+
+            kmq_create_subscription(afs_plugin_cb, &afs_sub);
+            ct.sub = afs_sub;
+
+            kcdb_credtype_register(&ct, &afs_credtype_id);
+
+            /* register the attribute types */
+            {
+                kcdb_type type;
+
+                ZeroMemory(&type, sizeof(type));
+                type.comp = afs_type_principal_comp;
+                type.dup = afs_type_principal_dup;
+                type.isValid = afs_type_principal_isValid;
+                type.toString = afs_type_principal_toString;
+                type.name = AFS_TYPENAME_PRINCIPAL;
+                type.id = KCDB_TYPE_INVALID;
+                type.cb_max = sizeof(struct ktc_principal);
+                type.cb_min = sizeof(struct ktc_principal);
+                type.flags = KCDB_TYPE_FLAG_CB_FIXED;
+
+                if(KHM_FAILED(kcdb_type_register(&type, 
+                                                 &afs_type_principal)))
+                    goto _exit_init;
+            }
+
+            {
+                kcdb_type type;
+                kcdb_type *ti32 = NULL;
+
+                kcdb_type_get_info(KCDB_TYPE_INT32, &ti32);
+
+                ZeroMemory(&type, sizeof(type));
+                type.comp = ti32->comp;
+                type.dup = ti32->dup;
+                type.isValid = ti32->isValid;
+                type.toString = afs_type_method_toString;
+                type.name = AFS_TYPENAME_METHOD;
+                type.id = KCDB_TYPE_INVALID;
+                type.cb_max = sizeof(khm_int32);
+                type.cb_min = sizeof(khm_int32);
+                type.flags = KCDB_TYPE_FLAG_CB_FIXED;
+
+                if(KHM_FAILED(kcdb_type_register(&type, 
+                                                 &afs_type_method))) {
+                    kcdb_type_release_info(ti32);
+                    goto _exit_init;
+                }
+
+                kcdb_type_release_info(ti32);
+            }
+
+            /* now register the attributes */
+            {
+                wchar_t short_desc[KCDB_MAXCCH_SHORT_DESC];
+                    
+                ZeroMemory(&att, sizeof(att));
+
+                att.type = KCDB_TYPE_STRING;
+                att.name = AFS_ATTRNAME_CELL;
+                LoadString(hResModule, 
+                           IDS_ATTR_CELL_SHORT_DESC, 
+                           short_desc, 
+                           ARRAYLENGTH(short_desc));
+                att.short_desc = short_desc;
+                att.long_desc = NULL;
+                att.id = KCDB_ATTR_INVALID;
+                att.flags = KCDB_ATTR_FLAG_TRANSIENT;
+                    
+                if(KHM_FAILED(rv = kcdb_attrib_register(&att, 
+                                                        &afs_attr_cell)))
+                    goto _exit_init;
+            }
+
+            {
+                wchar_t short_desc[KCDB_MAXCCH_SHORT_DESC];
+                    
+                ZeroMemory(&att, sizeof(att));
+
+                att.type = KCDB_TYPE_STRING;
+                att.name = AFS_ATTRNAME_REALM;
+                LoadString(hResModule, 
+                           IDS_ATTR_REALM_SHORT_DESC, 
+                           short_desc, 
+                           ARRAYLENGTH(short_desc));
+                att.short_desc = short_desc;
+                att.long_desc = NULL;
+                att.id = KCDB_ATTR_INVALID;
+                att.flags = KCDB_ATTR_FLAG_TRANSIENT;
+                    
+                if(KHM_FAILED(rv = kcdb_attrib_register(&att, 
+                                                        &afs_attr_realm)))
+                    goto _exit_init;
+            }
+
+            {
+                wchar_t short_desc[KCDB_MAXCCH_SHORT_DESC];
+                    
+                ZeroMemory(&att, sizeof(att));
+
+                att.type = afs_type_method;
+                att.name = AFS_ATTRNAME_METHOD;
+                LoadString(hResModule, 
+                           IDS_ATTR_METHOD_SHORT_DESC, 
+                           short_desc, 
+                           ARRAYLENGTH(short_desc));
+                att.short_desc = short_desc;
+                att.long_desc = NULL;
+                att.id = KCDB_ATTR_INVALID;
+                att.flags = KCDB_ATTR_FLAG_TRANSIENT;
+                    
+                if(KHM_FAILED(rv = kcdb_attrib_register(&att, 
+                                                        &afs_attr_method)))
+                    goto _exit_init;
+            }
+
+            {
+                wchar_t short_desc[KCDB_MAXCCH_SHORT_DESC];
+
+                ZeroMemory(&att, sizeof(att));
+
+                att.type = afs_type_principal;
+                att.name = AFS_ATTRNAME_CLIENT_PRINC;
+                LoadString(hResModule, 
+                           IDS_ATTR_CLIENT_PRINC_SHORT_DESC, 
+                           short_desc, 
+                           ARRAYLENGTH(short_desc));
+                att.short_desc = short_desc;
+                att.long_desc = NULL;
+                att.id = KCDB_ATTR_INVALID;
+                att.flags = KCDB_ATTR_FLAG_TRANSIENT;
+                    
+                if(KHM_FAILED(rv = kcdb_attrib_register(&att, &afs_attr_client_princ)))
+                    goto _exit_init;
+            }
+
+            {
+                wchar_t short_desc[KCDB_MAXCCH_SHORT_DESC];
+
+                ZeroMemory(&att, sizeof(att));
+
+                att.type = afs_type_principal;
+                att.name = AFS_ATTRNAME_SERVER_PRINC;
+                LoadString(hResModule, 
+                           IDS_ATTR_SERVER_PRINC_SHORT_DESC, 
+                           short_desc, ARRAYLENGTH(short_desc));
+                att.short_desc = short_desc;
+                att.long_desc = NULL;
+                att.id = KCDB_ATTR_INVALID;
+                att.flags = KCDB_ATTR_FLAG_TRANSIENT;
+                    
+                if(KHM_FAILED(rv = kcdb_attrib_register(&att, &afs_attr_server_princ)))
+                    goto _exit_init;
+            }
+
+            /* afs_credset is our stock credentials set that we
+               use for all our credset needs (instead of creating
+               a new one every time) */
+
+            if(KHM_FAILED(rv = kcdb_credset_create(&afs_credset)))
+                goto _exit_init;
+
+            if(KHM_FAILED(rv = kcdb_credtype_get_id(KRB5_CREDTYPE_NAME,
+                                                    &krb5_credtype_id)))
+                goto _exit_init;
+
+            /* register the configuration nodes */
+            {
+                khui_config_node node_ident;
+                khui_config_node_reg reg;
+                wchar_t wshort_desc[KHUI_MAXCCH_SHORT_DESC];
+                wchar_t wlong_desc[KHUI_MAXCCH_LONG_DESC];
+
+                if (KHM_FAILED(rv = khui_cfg_open(NULL,
+                                                  L"KhmIdentities",
+                                                  &node_ident)))
+                    goto _exit_init;
+
+                ZeroMemory(&reg, sizeof(reg));
+                reg.name = AFS_CONFIG_NODE_MAIN;
+                reg.short_desc = wshort_desc;
+                reg.long_desc = wlong_desc;
+                reg.h_module = hResModule;
+                reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_AFS);
+                reg.dlg_proc = afs_cfg_main_proc;
+                reg.flags = 0;
+                LoadString(hResModule, IDS_CFG_MAIN_LONG,
+                           wlong_desc, ARRAYLENGTH(wlong_desc));
+                LoadString(hResModule, IDS_CFG_MAIN_SHORT,
+                           wshort_desc, ARRAYLENGTH(wshort_desc));
+
+                khui_cfg_register(NULL, &reg);
+
+                ZeroMemory(&reg, sizeof(reg));
+                reg.name = AFS_CONFIG_NODE_IDS;
+                reg.short_desc = wshort_desc;
+                reg.long_desc = wshort_desc;
+                reg.h_module = hResModule;
+                reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_IDS_TAB);
+                reg.dlg_proc = afs_cfg_ids_proc;
+                reg.flags = KHUI_CNFLAG_SUBPANEL;
+                LoadString(hResModule, IDS_CFG_IDS_TAB,
+                           wshort_desc, ARRAYLENGTH(wshort_desc));
+
+                khui_cfg_register(node_ident, &reg);
+
+                ZeroMemory(&reg, sizeof(reg));
+                reg.name = AFS_CONFIG_NODE_ID;
+                reg.short_desc = wshort_desc;
+                reg.long_desc = wshort_desc;
+                reg.h_module = hResModule;
+                reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_ID_TAB);
+                reg.dlg_proc = afs_cfg_id_proc;
+                reg.flags = KHUI_CNFLAG_SUBPANEL | KHUI_CNFLAG_PLURAL;
+                LoadString(hResModule, IDS_CFG_ID_TAB,
+                           wshort_desc, ARRAYLENGTH(wshort_desc));
+
+                khui_cfg_register(node_ident, &reg);
+            }
+
+            /* and register the AFS message type */
+            rv = kmq_register_type(AFS_MSG_TYPENAME, &afs_msg_type_id);
+
+            if (KHM_SUCCEEDED(rv))
+                kmq_subscribe(afs_msg_type_id, afs_plugin_cb);
+
+            /* if the configuration is set to disable afscreds.exe,
+               then we look for the shortcut and remove it if
+               found. */
+            if (KHM_SUCCEEDED(kmm_get_plugin_config(AFS_PLUGIN_NAME,
+                                                    0,
+                                                    &csp_afscred))) {
+                wchar_t wpath[MAX_PATH];
+
+                khc_read_int32(csp_afscred, L"Disableafscreds",
+                               &disable_afscreds);
+
+                if (disable_afscreds &&
+                    afs_cfg_get_afscreds_shortcut(wpath)) {
+
+                    DeleteFile(wpath);
+
+                }
+
+                khc_close_space(csp_afscred);
+            }
+
+        _exit_init:
+            if(ct.short_desc)
+                PFREE(ct.short_desc);
+            if(ct.long_desc)
+                PFREE(ct.long_desc);
+        }
+        /* now that the critical stuff is done, we move on to the
+           non-critical stuff */
+        if(KHM_SUCCEEDED(rv)) {
+            initialized = TRUE;
+
+            /* obtain existing tokens */
+            afs_list_tokens();
+        }
+
+        /* define this so that if there are no TGT's, we don't
+           deadlock trying to open a new creds dialog from within the
+           new creds dialog. */
+        SetEnvironmentVariable(L"KERBEROSLOGIN_NEVER_PROMPT", L"1");
+
+        break;
+        /* end of KMSG_SYSTEM_INIT */
+
+    case KMSG_SYSTEM_EXIT:
+        if (afs_msg_type_id != -1) {
+            kmq_unsubscribe(afs_msg_type_id, afs_plugin_cb);
+            kmq_unregister_type(afs_msg_type_id);
+        }
+        if(afs_credtype_id >= 0) {
+            kcdb_credtype_unregister(afs_credtype_id);
+        }
+#if 0
+        if(afs_attr_client >= 0) {
+            kcdb_attrib_unregister(afs_attr_client);
+        }
+#endif
+        if(afs_attr_cell >= 0) {
+            kcdb_attrib_unregister(afs_attr_cell);
+        }
+        if(afs_attr_realm >= 0) {
+            kcdb_attrib_unregister(afs_attr_realm);
+        }
+        if(afs_attr_method >= 0) {
+            kcdb_attrib_unregister(afs_attr_method);
+        }
+        if(afs_attr_client_princ >= 0) {
+            kcdb_attrib_unregister(afs_attr_client_princ);
+        }
+        if(afs_attr_server_princ >= 0) {
+            kcdb_attrib_unregister(afs_attr_server_princ);
+        }
+        if(afs_type_principal >= 0) {
+            kcdb_type_unregister(afs_type_principal);
+        }
+        if(afs_type_method >= 0) {
+            kcdb_type_unregister(afs_type_method);
+        }
+        initialized = FALSE;
+        if(afs_credset)
+            kcdb_credset_delete(afs_credset);
+
+        /* afs_sub doesn't need to be deleted.  That is taken care
+           of when unregistering the afs cred type */
+        afs_sub = NULL;
+
+        rv = KHM_ERROR_SUCCESS;
+        break;
+        /* end of KMSG_SYSTEM_EXIT */
+    }
+    return rv;
+}
+
+/* process KMSG_KCDB messages */
+khm_int32 KHMAPI 
+afs_msg_kcdb(khm_int32 msg_subtype, 
+             khm_ui_4 uparam, 
+             void * vparam)
+{
+    khm_int32 rv = KHM_ERROR_SUCCESS;
+
+    /* we don't really do anything with this yet */
+#if 0
+    switch(msg_subtype) {
+    }
+#endif
+
+    return rv;
+}
+
+
+
+static khm_int32 KHMAPI
+afs_cred_destroy_proc(khm_handle cred, void * rock) {
+    khm_int32 t;
+
+    if (KHM_FAILED(kcdb_cred_get_type(cred, &t)) ||
+        t != afs_credtype_id)
+        return KHM_ERROR_SUCCESS;
+
+    afs_unlog_cred(cred);
+
+    return KHM_ERROR_SUCCESS;
+}
+
+/* process KMSG_CRED messages */
+khm_int32 KHMAPI 
+afs_msg_cred(khm_int32 msg_subtype, 
+             khm_ui_4 uparam, 
+             void * vparam)
+{
+    khm_int32 rv = KHM_ERROR_SUCCESS;
+
+    switch(msg_subtype) {
+    case KMSG_CRED_REFRESH:
+        afs_list_tokens();
+        break;
+
+    case KMSG_CRED_DESTROY_CREDS:
+        {
+            khui_action_context * ctx;
+
+            ctx = (khui_action_context *) vparam;
+
+            if (ctx->credset) {
+                _begin_task(0);
+                _report_cs0(KHERR_INFO, L"Destroying AFS Tokens");
+                _describe();
+
+                kcdb_credset_apply(ctx->credset,
+                                   afs_cred_destroy_proc,
+                                   NULL);
+
+                _end_task();
+            }
+        }
+        break;
+
+    default:
+
+        if (IS_CRED_ACQ_MSG(msg_subtype))
+            return afs_msg_newcred(msg_subtype, uparam, vparam);
+    }
+
+    return rv;
+}
+
diff --git a/src/WINNT/netidmgr_plugin/afsplugin_custom.c b/src/WINNT/netidmgr_plugin/afsplugin_custom.c
new file mode 100644 (file)
index 0000000..d32b878
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2004 Massachusetts Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* $Id$ */
+
+#include<windows.h>
+#include<msiquery.h>
+#include<tchar.h>
+
+static
+const TCHAR * const dword_props[] = {
+    _TEXT("OPENAFSVERSIONMAJOR"),
+    _TEXT("OPENAFSVERSIONMINOR"),
+    _TEXT("KFWVERSIONMAJOR")
+};
+
+static void strip_decoration(TCHAR * str, int cchlen) {
+    int i;
+
+    if (str[0] != _T('#') || cchlen < 1)
+        return;
+
+    for (i=1; i < cchlen && str[i]; i++) {
+        str[i-1] = str[i];
+    }
+
+    str[i-1] = _T('\0');
+}
+
+UINT __stdcall StripRegDecoration(MSIHANDLE hInstall) {
+    TCHAR propbuffer[16];      /* we are looking for string
+                                  representations of DOWRDs.  They
+                                  can't be longer than this. */
+    DWORD cch_buffer;
+    UINT rv;
+    int i;
+
+    for (i=0; i < sizeof(dword_props)/sizeof(dword_props[0]); i++) {
+        cch_buffer = sizeof(propbuffer)/sizeof(propbuffer[0]);
+        rv = MsiGetProperty(hInstall, dword_props[i], propbuffer, &cch_buffer);
+        if (rv == ERROR_SUCCESS) {
+            strip_decoration(propbuffer, cch_buffer);
+            MsiSetProperty(hInstall, dword_props[i], propbuffer);
+        }
+    }
+
+    return ERROR_SUCCESS;
+}
diff --git a/src/WINNT/netidmgr_plugin/dynimport.c b/src/WINNT/netidmgr_plugin/dynimport.c
new file mode 100644 (file)
index 0000000..bb4b8bd
--- /dev/null
@@ -0,0 +1,463 @@
+/*
+* Copyright (c) 2005 Massachusetts Institute of Technology
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use, copy,
+* modify, merge, publish, distribute, sublicense, and/or sell copies
+* of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*/
+
+/* $Id$ */
+
+#include<windows.h>
+#include<khdefs.h>
+#include<kherror.h>
+#include<dynimport.h>
+
+HINSTANCE hKrb4 = 0;
+HINSTANCE hKrb5 = 0;
+HINSTANCE hKrb524 = 0;
+HINSTANCE hSecur32 = 0;
+HINSTANCE hComErr = 0;
+HINSTANCE hService = 0;
+HINSTANCE hProfile = 0;
+HINSTANCE hPsapi = 0; 
+HINSTANCE hToolHelp32 = 0; 
+HINSTANCE hCCAPI = 0;
+
+DWORD     AfsAvailable = 0;
+
+// CCAPI
+DECL_FUNC_PTR(cc_initialize);
+DECL_FUNC_PTR(cc_shutdown);
+DECL_FUNC_PTR(cc_get_NC_info);
+DECL_FUNC_PTR(cc_free_NC_info);
+
+// krb4 functions
+DECL_FUNC_PTR(get_krb_err_txt_entry);
+DECL_FUNC_PTR(k_isinst);
+DECL_FUNC_PTR(k_isname);
+DECL_FUNC_PTR(k_isrealm);
+DECL_FUNC_PTR(kadm_change_your_password);
+DECL_FUNC_PTR(kname_parse);
+DECL_FUNC_PTR(krb_get_cred);
+DECL_FUNC_PTR(krb_get_krbhst);
+DECL_FUNC_PTR(krb_get_lrealm);
+DECL_FUNC_PTR(krb_get_pw_in_tkt);
+DECL_FUNC_PTR(krb_get_tf_realm);
+DECL_FUNC_PTR(krb_mk_req);
+DECL_FUNC_PTR(krb_realmofhost);
+DECL_FUNC_PTR(tf_init);
+DECL_FUNC_PTR(tf_close);
+DECL_FUNC_PTR(tf_get_cred);
+DECL_FUNC_PTR(tf_get_pname);
+DECL_FUNC_PTR(tf_get_pinst);
+DECL_FUNC_PTR(LocalHostAddr);
+DECL_FUNC_PTR(tkt_string);
+DECL_FUNC_PTR(krb_set_tkt_string);
+DECL_FUNC_PTR(initialize_krb_error_func);
+DECL_FUNC_PTR(initialize_kadm_error_table);
+DECL_FUNC_PTR(dest_tkt);
+DECL_FUNC_PTR(krb_in_tkt);
+DECL_FUNC_PTR(krb_save_credentials);
+DECL_FUNC_PTR(krb_get_krbconf2);
+DECL_FUNC_PTR(krb_get_krbrealm2);
+DECL_FUNC_PTR(krb_life_to_time);
+
+// krb5 functions
+DECL_FUNC_PTR(krb5_change_password);
+DECL_FUNC_PTR(krb5_get_init_creds_opt_init);
+DECL_FUNC_PTR(krb5_get_init_creds_opt_set_tkt_life);
+DECL_FUNC_PTR(krb5_get_init_creds_opt_set_renew_life);
+DECL_FUNC_PTR(krb5_get_init_creds_opt_set_forwardable);
+DECL_FUNC_PTR(krb5_get_init_creds_opt_set_proxiable);
+DECL_FUNC_PTR(krb5_get_init_creds_opt_set_address_list);
+DECL_FUNC_PTR(krb5_get_init_creds_password);
+DECL_FUNC_PTR(krb5_get_prompt_types);
+DECL_FUNC_PTR(krb5_build_principal_ext);
+DECL_FUNC_PTR(krb5_cc_get_name);
+DECL_FUNC_PTR(krb5_cc_get_type);
+DECL_FUNC_PTR(krb5_cc_resolve);
+DECL_FUNC_PTR(krb5_cc_default);
+DECL_FUNC_PTR(krb5_cc_default_name);
+DECL_FUNC_PTR(krb5_cc_set_default_name);
+DECL_FUNC_PTR(krb5_cc_initialize);
+DECL_FUNC_PTR(krb5_cc_destroy);
+DECL_FUNC_PTR(krb5_cc_close);
+DECL_FUNC_PTR(krb5_cc_store_cred);
+DECL_FUNC_PTR(krb5_cc_copy_creds);
+DECL_FUNC_PTR(krb5_cc_retrieve_cred);
+DECL_FUNC_PTR(krb5_cc_get_principal);
+DECL_FUNC_PTR(krb5_cc_start_seq_get);
+DECL_FUNC_PTR(krb5_cc_next_cred);
+DECL_FUNC_PTR(krb5_cc_end_seq_get);
+DECL_FUNC_PTR(krb5_cc_remove_cred);
+DECL_FUNC_PTR(krb5_cc_set_flags);
+// DECL_FUNC_PTR(krb5_cc_get_type);
+DECL_FUNC_PTR(krb5_free_context);
+DECL_FUNC_PTR(krb5_free_cred_contents);
+DECL_FUNC_PTR(krb5_free_principal);
+DECL_FUNC_PTR(krb5_get_in_tkt_with_password);
+DECL_FUNC_PTR(krb5_init_context);
+DECL_FUNC_PTR(krb5_parse_name);
+DECL_FUNC_PTR(krb5_timeofday);
+DECL_FUNC_PTR(krb5_timestamp_to_sfstring);
+DECL_FUNC_PTR(krb5_unparse_name);
+DECL_FUNC_PTR(krb5_get_credentials);
+DECL_FUNC_PTR(krb5_mk_req);
+DECL_FUNC_PTR(krb5_sname_to_principal);
+DECL_FUNC_PTR(krb5_get_credentials_renew);
+DECL_FUNC_PTR(krb5_free_data);
+DECL_FUNC_PTR(krb5_free_data_contents);
+// DECL_FUNC_PTR(krb5_get_realm_domain);
+DECL_FUNC_PTR(krb5_free_unparsed_name);
+DECL_FUNC_PTR(krb5_os_localaddr);
+DECL_FUNC_PTR(krb5_copy_keyblock_contents);
+DECL_FUNC_PTR(krb5_copy_data);
+DECL_FUNC_PTR(krb5_free_creds);
+DECL_FUNC_PTR(krb5_build_principal);
+DECL_FUNC_PTR(krb5_get_renewed_creds);
+DECL_FUNC_PTR(krb5_get_default_config_files);
+DECL_FUNC_PTR(krb5_free_config_files);
+DECL_FUNC_PTR(krb5_get_default_realm);
+DECL_FUNC_PTR(krb5_set_default_realm);
+DECL_FUNC_PTR(krb5_free_ticket);
+DECL_FUNC_PTR(krb5_decode_ticket);
+DECL_FUNC_PTR(krb5_get_host_realm);
+DECL_FUNC_PTR(krb5_free_host_realm);
+DECL_FUNC_PTR(krb5_c_random_make_octets);
+DECL_FUNC_PTR(krb5_free_addresses);
+DECL_FUNC_PTR(krb5_free_default_realm);
+
+// Krb524 functions
+DECL_FUNC_PTR(krb524_init_ets);
+DECL_FUNC_PTR(krb524_convert_creds_kdc);
+
+// ComErr functions
+DECL_FUNC_PTR(com_err);
+DECL_FUNC_PTR(error_message);
+
+// Profile functions
+DECL_FUNC_PTR(profile_init);    
+DECL_FUNC_PTR(profile_flush);
+DECL_FUNC_PTR(profile_release); 
+DECL_FUNC_PTR(profile_get_subsection_names);
+DECL_FUNC_PTR(profile_free_list);
+DECL_FUNC_PTR(profile_get_string);
+DECL_FUNC_PTR(profile_get_values);
+DECL_FUNC_PTR(profile_get_relation_names);
+DECL_FUNC_PTR(profile_clear_relation);
+DECL_FUNC_PTR(profile_add_relation);
+DECL_FUNC_PTR(profile_update_relation);
+DECL_FUNC_PTR(profile_release_string);
+
+// Service functions
+DECL_FUNC_PTR(OpenSCManagerA);
+DECL_FUNC_PTR(OpenServiceA);
+DECL_FUNC_PTR(QueryServiceStatus);
+DECL_FUNC_PTR(CloseServiceHandle);
+DECL_FUNC_PTR(LsaNtStatusToWinError);
+
+// LSA Functions
+DECL_FUNC_PTR(LsaConnectUntrusted);
+DECL_FUNC_PTR(LsaLookupAuthenticationPackage);
+DECL_FUNC_PTR(LsaCallAuthenticationPackage);
+DECL_FUNC_PTR(LsaFreeReturnBuffer);
+DECL_FUNC_PTR(LsaGetLogonSessionData);
+
+// CCAPI
+FUNC_INFO ccapi_fi[] = {
+    MAKE_FUNC_INFO(cc_initialize),
+    MAKE_FUNC_INFO(cc_shutdown),
+    MAKE_FUNC_INFO(cc_get_NC_info),
+    MAKE_FUNC_INFO(cc_free_NC_info),
+    END_FUNC_INFO
+};
+
+FUNC_INFO k4_fi[] = {
+    MAKE_FUNC_INFO(get_krb_err_txt_entry),
+    MAKE_FUNC_INFO(k_isinst),
+    MAKE_FUNC_INFO(k_isname),
+    MAKE_FUNC_INFO(k_isrealm),
+    MAKE_FUNC_INFO(kadm_change_your_password),
+    MAKE_FUNC_INFO(kname_parse),
+    MAKE_FUNC_INFO(krb_get_cred),
+    MAKE_FUNC_INFO(krb_get_krbhst),
+    MAKE_FUNC_INFO(krb_get_lrealm),
+    MAKE_FUNC_INFO(krb_get_pw_in_tkt),
+    MAKE_FUNC_INFO(krb_get_tf_realm),
+    MAKE_FUNC_INFO(krb_mk_req),
+    MAKE_FUNC_INFO(krb_realmofhost),
+    MAKE_FUNC_INFO(tf_init),
+    MAKE_FUNC_INFO(tf_close),
+    MAKE_FUNC_INFO(tf_get_cred),
+    MAKE_FUNC_INFO(tf_get_pname),
+    MAKE_FUNC_INFO(tf_get_pinst),
+    MAKE_FUNC_INFO(LocalHostAddr),
+    MAKE_FUNC_INFO(tkt_string),
+    MAKE_FUNC_INFO(krb_set_tkt_string),
+    MAKE_FUNC_INFO(initialize_krb_error_func),
+    MAKE_FUNC_INFO(initialize_kadm_error_table),
+    MAKE_FUNC_INFO(dest_tkt),
+    /*        MAKE_FUNC_INFO(lsh_LoadKrb4LeashErrorTables), */// XXX
+    MAKE_FUNC_INFO(krb_in_tkt),
+    MAKE_FUNC_INFO(krb_save_credentials),
+    MAKE_FUNC_INFO(krb_get_krbconf2),
+    MAKE_FUNC_INFO(krb_get_krbrealm2),
+    MAKE_FUNC_INFO(krb_life_to_time),
+    END_FUNC_INFO
+};
+
+FUNC_INFO k5_fi[] = {
+    MAKE_FUNC_INFO(krb5_change_password),
+    MAKE_FUNC_INFO(krb5_get_init_creds_opt_init),
+    MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_tkt_life),
+    MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_renew_life),
+    MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_forwardable),
+    MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_proxiable),
+    MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_address_list),
+    MAKE_FUNC_INFO(krb5_get_init_creds_password),
+    MAKE_FUNC_INFO(krb5_get_prompt_types),
+    MAKE_FUNC_INFO(krb5_build_principal_ext),
+    MAKE_FUNC_INFO(krb5_cc_get_name),
+    MAKE_FUNC_INFO(krb5_cc_get_type),
+    MAKE_FUNC_INFO(krb5_cc_resolve),
+    MAKE_FUNC_INFO(krb5_cc_default),
+    MAKE_FUNC_INFO(krb5_cc_default_name),
+    MAKE_FUNC_INFO(krb5_cc_set_default_name),
+    MAKE_FUNC_INFO(krb5_cc_initialize),
+    MAKE_FUNC_INFO(krb5_cc_destroy),
+    MAKE_FUNC_INFO(krb5_cc_close),
+    MAKE_FUNC_INFO(krb5_cc_copy_creds),
+    MAKE_FUNC_INFO(krb5_cc_store_cred),
+    MAKE_FUNC_INFO(krb5_cc_retrieve_cred),
+    MAKE_FUNC_INFO(krb5_cc_get_principal),
+    MAKE_FUNC_INFO(krb5_cc_start_seq_get),
+    MAKE_FUNC_INFO(krb5_cc_next_cred),
+    MAKE_FUNC_INFO(krb5_cc_end_seq_get),
+    MAKE_FUNC_INFO(krb5_cc_remove_cred),
+    MAKE_FUNC_INFO(krb5_cc_set_flags),
+    // MAKE_FUNC_INFO(krb5_cc_get_type),
+    MAKE_FUNC_INFO(krb5_free_context),
+    MAKE_FUNC_INFO(krb5_free_cred_contents),
+    MAKE_FUNC_INFO(krb5_free_principal),
+    MAKE_FUNC_INFO(krb5_get_in_tkt_with_password),
+    MAKE_FUNC_INFO(krb5_init_context),
+    MAKE_FUNC_INFO(krb5_parse_name),
+    MAKE_FUNC_INFO(krb5_timeofday),
+    MAKE_FUNC_INFO(krb5_timestamp_to_sfstring),
+    MAKE_FUNC_INFO(krb5_unparse_name),
+    MAKE_FUNC_INFO(krb5_get_credentials),
+    MAKE_FUNC_INFO(krb5_mk_req),
+    MAKE_FUNC_INFO(krb5_sname_to_principal),
+    MAKE_FUNC_INFO(krb5_get_credentials_renew),
+    MAKE_FUNC_INFO(krb5_free_data),
+    MAKE_FUNC_INFO(krb5_free_data_contents),
+    //  MAKE_FUNC_INFO(krb5_get_realm_domain),
+    MAKE_FUNC_INFO(krb5_free_unparsed_name),
+    MAKE_FUNC_INFO(krb5_os_localaddr),
+    MAKE_FUNC_INFO(krb5_copy_keyblock_contents),
+    MAKE_FUNC_INFO(krb5_copy_data),
+    MAKE_FUNC_INFO(krb5_free_creds),
+    MAKE_FUNC_INFO(krb5_build_principal),
+    MAKE_FUNC_INFO(krb5_get_renewed_creds),
+    MAKE_FUNC_INFO(krb5_free_addresses),
+    MAKE_FUNC_INFO(krb5_get_default_config_files),
+    MAKE_FUNC_INFO(krb5_free_config_files),
+    MAKE_FUNC_INFO(krb5_get_default_realm),
+    MAKE_FUNC_INFO(krb5_set_default_realm),
+    MAKE_FUNC_INFO(krb5_free_ticket),
+    MAKE_FUNC_INFO(krb5_decode_ticket),
+    MAKE_FUNC_INFO(krb5_get_host_realm),
+    MAKE_FUNC_INFO(krb5_free_host_realm),
+    MAKE_FUNC_INFO(krb5_c_random_make_octets),
+    MAKE_FUNC_INFO(krb5_free_default_realm),
+    END_FUNC_INFO
+};
+
+FUNC_INFO k524_fi[] = {
+    MAKE_FUNC_INFO(krb524_init_ets),
+    MAKE_FUNC_INFO(krb524_convert_creds_kdc),
+    END_FUNC_INFO
+};
+
+FUNC_INFO profile_fi[] = {
+    MAKE_FUNC_INFO(profile_init),
+    MAKE_FUNC_INFO(profile_flush),
+    MAKE_FUNC_INFO(profile_release), 
+    MAKE_FUNC_INFO(profile_get_subsection_names),
+    MAKE_FUNC_INFO(profile_free_list),
+    MAKE_FUNC_INFO(profile_get_string),
+    MAKE_FUNC_INFO(profile_get_values),
+    MAKE_FUNC_INFO(profile_get_relation_names),
+    MAKE_FUNC_INFO(profile_clear_relation),
+    MAKE_FUNC_INFO(profile_add_relation),
+    MAKE_FUNC_INFO(profile_update_relation),
+    MAKE_FUNC_INFO(profile_release_string),
+    END_FUNC_INFO
+};
+
+FUNC_INFO ce_fi[] = {
+    MAKE_FUNC_INFO(com_err),
+    MAKE_FUNC_INFO(error_message),
+    END_FUNC_INFO
+};
+
+FUNC_INFO service_fi[] = {
+    MAKE_FUNC_INFO(OpenSCManagerA),
+    MAKE_FUNC_INFO(OpenServiceA),
+    MAKE_FUNC_INFO(QueryServiceStatus),
+    MAKE_FUNC_INFO(CloseServiceHandle),
+    MAKE_FUNC_INFO(LsaNtStatusToWinError),
+    END_FUNC_INFO
+};
+
+FUNC_INFO lsa_fi[] = {
+    MAKE_FUNC_INFO(LsaConnectUntrusted),
+    MAKE_FUNC_INFO(LsaLookupAuthenticationPackage),
+    MAKE_FUNC_INFO(LsaCallAuthenticationPackage),
+    MAKE_FUNC_INFO(LsaFreeReturnBuffer),
+    MAKE_FUNC_INFO(LsaGetLogonSessionData),
+    END_FUNC_INFO
+};
+
+// psapi functions
+DECL_FUNC_PTR(GetModuleFileNameExA);
+DECL_FUNC_PTR(EnumProcessModules);
+
+FUNC_INFO psapi_fi[] = {
+    MAKE_FUNC_INFO(GetModuleFileNameExA),
+        MAKE_FUNC_INFO(EnumProcessModules),
+        END_FUNC_INFO
+};
+
+// toolhelp functions
+DECL_FUNC_PTR(CreateToolhelp32Snapshot);
+DECL_FUNC_PTR(Module32First);
+DECL_FUNC_PTR(Module32Next);
+
+FUNC_INFO toolhelp_fi[] = {
+    MAKE_FUNC_INFO(CreateToolhelp32Snapshot),
+        MAKE_FUNC_INFO(Module32First),
+        MAKE_FUNC_INFO(Module32Next),
+        END_FUNC_INFO
+};
+
+khm_int32 init_imports(void) {
+    OSVERSIONINFO osvi;
+    int imp_rv = 1;
+
+#define CKRV if(!imp_rv) goto _err_ret
+
+#ifndef _WIN64
+    imp_rv = LoadFuncs(KRB4_DLL, k4_fi, &hKrb4, 0, 1, 0, 0);
+    CKRV;
+#endif
+
+    imp_rv = LoadFuncs(KRB5_DLL, k5_fi, &hKrb5, 0, 1, 0, 0);
+    CKRV;
+
+    imp_rv = LoadFuncs(COMERR_DLL, ce_fi, &hComErr, 0, 0, 1, 0);
+    CKRV;
+
+    imp_rv = LoadFuncs(SERVICE_DLL, service_fi, &hService, 0, 1, 0, 0);
+    CKRV;
+
+    imp_rv = LoadFuncs(SECUR32_DLL, lsa_fi, &hSecur32, 0, 1, 1, 1);
+    CKRV;
+
+    imp_rv = LoadFuncs(KRB524_DLL, k524_fi, &hKrb524, 0, 1, 1, 1);
+    CKRV;
+
+    imp_rv = LoadFuncs(PROFILE_DLL, profile_fi, &hProfile, 0, 1, 0, 0);
+    CKRV;
+
+    imp_rv = LoadFuncs(CCAPI_DLL, ccapi_fi, &hCCAPI, 0, 1, 0, 0);
+    /* CCAPI_DLL is optional.  No error check. */
+
+    memset(&osvi, 0, sizeof(OSVERSIONINFO));
+    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+    GetVersionEx(&osvi);
+
+    // XXX: We should really use feature testing, first
+    // checking for CreateToolhelp32Snapshot.  If that's
+    // not around, we try the psapi stuff.
+    //
+    // Only load LSA functions if on NT/2000/XP
+    if(osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
+    {
+        // Windows 9x
+        imp_rv = LoadFuncs(TOOLHELPDLL, toolhelp_fi, &hToolHelp32, 0, 1, 0, 0);
+        CKRV;
+
+        hPsapi = 0;
+    }             
+    else if(osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)
+    {
+        // Windows NT
+        imp_rv = LoadFuncs(PSAPIDLL, psapi_fi, &hPsapi, 0, 1, 0, 0);
+        CKRV;
+
+        hToolHelp32 = 0;
+    }
+
+    AfsAvailable = TRUE; //afscompat_init();
+
+    return KHM_ERROR_SUCCESS;
+
+ _err_ret:
+    return KHM_ERROR_NOT_FOUND;
+}
+
+khm_int32 exit_imports(void) {
+    //afscompat_close();
+
+    if (hKrb4)
+        FreeLibrary(hKrb4);
+    if (hKrb5)
+        FreeLibrary(hKrb5);
+    if (hProfile)
+        FreeLibrary(hProfile);
+    if (hComErr)
+        FreeLibrary(hComErr);
+    if (hService)
+        FreeLibrary(hService);
+    if (hSecur32)
+        FreeLibrary(hSecur32);
+    if (hKrb524)
+        FreeLibrary(hKrb524);
+    if (hPsapi)
+        FreeLibrary(hPsapi);
+    if (hToolHelp32)
+        FreeLibrary(hToolHelp32);
+
+    return KHM_ERROR_SUCCESS;
+}
+
+int (*Lcom_err)(LPSTR,long,LPSTR,...);
+LPSTR (*Lerror_message)(long);
+LPSTR (*Lerror_table_name)(long);
+
+void Leash_load_com_err_callback(FARPROC ce,
+                                 FARPROC em,
+                                 FARPROC etn)
+{
+    (FARPROC)Lcom_err=ce;
+    (FARPROC)Lerror_message=em;
+    (FARPROC)Lerror_table_name=etn;
+}
diff --git a/src/WINNT/netidmgr_plugin/dynimport.h b/src/WINNT/netidmgr_plugin/dynimport.h
new file mode 100644 (file)
index 0000000..46c72e0
--- /dev/null
@@ -0,0 +1,350 @@
+/*
+ * Copyright (c) 2005 Massachusetts Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* $Id$ */
+
+#ifndef __KHIMAIRA_DYNIMPORT_H
+#define __KHIMAIRA_DYNIMPORT_H
+
+/* Dynamic imports */
+#include<khdefs.h>
+#include<tlhelp32.h>
+#include<ntsecapi.h>
+
+#ifndef FAR
+#define FAR
+#endif
+
+extern HINSTANCE hKrb4;
+extern HINSTANCE hKrb5;
+extern HINSTANCE hProfile;
+
+///////////////////////////////////////////////////////////////////////////////
+
+#define CCAPI_DLL     "krbcc32.dll"
+#define KRBCC32_DLL   "krbcc32.dll"
+#define SERVICE_DLL   "advapi32.dll"
+#define SECUR32_DLL   "secur32.dll"
+#define PROFILE_DLL   "xpprof32.dll"
+
+//////////////////////////////////////////////////////////////////////////////
+
+#include <loadfuncs-com_err.h>
+#include <loadfuncs-krb5.h>
+#include <loadfuncs-profile.h>
+#include <loadfuncs-krb.h>
+#include <loadfuncs-krb524.h>
+#include <loadfuncs-lsa.h>
+
+//// CCAPI
+/* In order to avoid including the private CCAPI headers */
+typedef int cc_int32;
+
+#define CC_API_VER_1 1
+#define CC_API_VER_2 2
+
+#define CCACHE_API cc_int32
+
+/*
+** The Official Error Codes
+*/
+#define CC_NOERROR           0
+#define CC_BADNAME           1
+#define CC_NOTFOUND          2
+#define CC_END               3
+#define CC_IO                4
+#define CC_WRITE             5
+#define CC_NOMEM             6
+#define CC_FORMAT            7
+#define CC_LOCKED            8
+#define CC_BAD_API_VERSION   9
+#define CC_NO_EXIST          10
+#define CC_NOT_SUPP          11
+#define CC_BAD_PARM          12
+#define CC_ERR_CACHE_ATTACH  13
+#define CC_ERR_CACHE_RELEASE 14
+#define CC_ERR_CACHE_FULL    15
+#define CC_ERR_CRED_VERSION  16
+
+enum {
+    CC_CRED_VUNKNOWN = 0,       // For validation
+    CC_CRED_V4 = 1,
+    CC_CRED_V5 = 2,
+    CC_CRED_VMAX = 3            // For validation
+};
+
+typedef struct opaque_dll_control_block_type* apiCB;
+typedef struct _infoNC {
+    char*     name;
+    char*     principal;
+    cc_int32  vers;
+} infoNC;
+
+TYPEDEF_FUNC(
+CCACHE_API,
+CALLCONV_C,
+cc_initialize,
+    (
+    apiCB** cc_ctx,           // <  DLL's primary control structure.
+                              //    returned here, passed everywhere else
+    cc_int32 api_version,     // >  ver supported by caller (use CC_API_VER_1)
+    cc_int32*  api_supported, // <  if ~NULL, max ver supported by DLL
+    const char** vendor       // <  if ~NULL, vendor name in read only C string
+    )
+);
+
+TYPEDEF_FUNC(
+CCACHE_API,
+CALLCONV_C,
+cc_shutdown,
+    (
+    apiCB** cc_ctx            // <> DLL's primary control structure. NULL after
+    )
+);
+
+TYPEDEF_FUNC(
+CCACHE_API,
+CALLCONV_C,
+cc_get_NC_info,
+    (
+    apiCB* cc_ctx,          // >  DLL's primary control structure
+    struct _infoNC*** ppNCi // <  (NULL before call) null terminated,
+                            //    list of a structs (free via cc_free_infoNC())
+    )
+);
+
+TYPEDEF_FUNC(
+CCACHE_API,
+CALLCONV_C,
+cc_free_NC_info,
+    (
+    apiCB* cc_ctx,
+    struct _infoNC*** ppNCi // <  free list of structs returned by
+                            //    cc_get_cache_names().  set to NULL on return
+    )
+);
+//// \CCAPI
+
+extern  DWORD AfsAvailable;
+
+// service definitions
+typedef SC_HANDLE (WINAPI *FP_OpenSCManagerA)(char *, char *, DWORD);
+typedef SC_HANDLE (WINAPI *FP_OpenServiceA)(SC_HANDLE, char *, DWORD);
+typedef BOOL (WINAPI *FP_QueryServiceStatus)(SC_HANDLE, LPSERVICE_STATUS);
+typedef BOOL (WINAPI *FP_CloseServiceHandle)(SC_HANDLE);
+
+//////////////////////////////////////////////////////////////////////////////
+
+// CCAPI
+extern DECL_FUNC_PTR(cc_initialize);
+extern DECL_FUNC_PTR(cc_shutdown);
+extern DECL_FUNC_PTR(cc_get_NC_info);
+extern DECL_FUNC_PTR(cc_free_NC_info);
+
+// krb4 functions
+extern DECL_FUNC_PTR(get_krb_err_txt_entry);
+extern DECL_FUNC_PTR(k_isinst);
+extern DECL_FUNC_PTR(k_isname);
+extern DECL_FUNC_PTR(k_isrealm);
+extern DECL_FUNC_PTR(kadm_change_your_password);
+extern DECL_FUNC_PTR(kname_parse);
+extern DECL_FUNC_PTR(krb_get_cred);
+extern DECL_FUNC_PTR(krb_get_krbhst);
+extern DECL_FUNC_PTR(krb_get_lrealm);
+extern DECL_FUNC_PTR(krb_get_pw_in_tkt);
+extern DECL_FUNC_PTR(krb_get_tf_realm);
+extern DECL_FUNC_PTR(krb_mk_req);
+extern DECL_FUNC_PTR(krb_realmofhost);
+extern DECL_FUNC_PTR(tf_init);
+extern DECL_FUNC_PTR(tf_close);
+extern DECL_FUNC_PTR(tf_get_cred);
+extern DECL_FUNC_PTR(tf_get_pname);
+extern DECL_FUNC_PTR(tf_get_pinst);
+extern DECL_FUNC_PTR(LocalHostAddr);
+extern DECL_FUNC_PTR(tkt_string);
+extern DECL_FUNC_PTR(krb_set_tkt_string);
+extern DECL_FUNC_PTR(initialize_krb_error_func);
+extern DECL_FUNC_PTR(initialize_kadm_error_table);
+extern DECL_FUNC_PTR(dest_tkt);
+extern DECL_FUNC_PTR(lsh_LoadKrb4LeashErrorTables); // XXX
+extern DECL_FUNC_PTR(krb_in_tkt);
+extern DECL_FUNC_PTR(krb_save_credentials);
+extern DECL_FUNC_PTR(krb_get_krbconf2);
+extern DECL_FUNC_PTR(krb_get_krbrealm2);
+extern DECL_FUNC_PTR(krb_life_to_time);
+
+// krb5 functions
+extern DECL_FUNC_PTR(krb5_change_password);
+extern DECL_FUNC_PTR(krb5_get_init_creds_opt_init);
+extern DECL_FUNC_PTR(krb5_get_init_creds_opt_set_tkt_life);
+extern DECL_FUNC_PTR(krb5_get_init_creds_opt_set_renew_life);
+extern DECL_FUNC_PTR(krb5_get_init_creds_opt_set_forwardable);
+extern DECL_FUNC_PTR(krb5_get_init_creds_opt_set_proxiable);
+extern DECL_FUNC_PTR(krb5_get_init_creds_opt_set_renew_life);
+extern DECL_FUNC_PTR(krb5_get_init_creds_opt_set_address_list);
+extern DECL_FUNC_PTR(krb5_get_init_creds_password);
+extern DECL_FUNC_PTR(krb5_get_prompt_types);
+extern DECL_FUNC_PTR(krb5_build_principal_ext);
+extern DECL_FUNC_PTR(krb5_cc_get_name);
+extern DECL_FUNC_PTR(krb5_cc_get_type);
+extern DECL_FUNC_PTR(krb5_cc_resolve);
+extern DECL_FUNC_PTR(krb5_cc_default);
+extern DECL_FUNC_PTR(krb5_cc_default_name);
+extern DECL_FUNC_PTR(krb5_cc_set_default_name);
+extern DECL_FUNC_PTR(krb5_cc_initialize);
+extern DECL_FUNC_PTR(krb5_cc_destroy);
+extern DECL_FUNC_PTR(krb5_cc_close);
+extern DECL_FUNC_PTR(krb5_cc_copy_creds);
+extern DECL_FUNC_PTR(krb5_cc_store_cred);
+extern DECL_FUNC_PTR(krb5_cc_retrieve_cred);
+extern DECL_FUNC_PTR(krb5_cc_get_principal);
+extern DECL_FUNC_PTR(krb5_cc_start_seq_get);
+extern DECL_FUNC_PTR(krb5_cc_next_cred);
+extern DECL_FUNC_PTR(krb5_cc_end_seq_get);
+extern DECL_FUNC_PTR(krb5_cc_remove_cred);
+extern DECL_FUNC_PTR(krb5_cc_set_flags);
+// extern DECL_FUNC_PTR(krb5_cc_get_type);
+extern DECL_FUNC_PTR(krb5_free_context);
+extern DECL_FUNC_PTR(krb5_free_cred_contents);
+extern DECL_FUNC_PTR(krb5_free_principal);
+extern DECL_FUNC_PTR(krb5_get_in_tkt_with_password);
+extern DECL_FUNC_PTR(krb5_init_context);
+extern DECL_FUNC_PTR(krb5_parse_name);
+extern DECL_FUNC_PTR(krb5_timeofday);
+extern DECL_FUNC_PTR(krb5_timestamp_to_sfstring);
+extern DECL_FUNC_PTR(krb5_unparse_name);
+extern DECL_FUNC_PTR(krb5_get_credentials);
+extern DECL_FUNC_PTR(krb5_mk_req);
+extern DECL_FUNC_PTR(krb5_sname_to_principal);
+extern DECL_FUNC_PTR(krb5_get_credentials_renew);
+extern DECL_FUNC_PTR(krb5_free_data);
+extern DECL_FUNC_PTR(krb5_free_data_contents);
+// extern DECL_FUNC_PTR(krb5_get_realm_domain);
+extern DECL_FUNC_PTR(krb5_free_unparsed_name);
+extern DECL_FUNC_PTR(krb5_os_localaddr);
+extern DECL_FUNC_PTR(krb5_copy_keyblock_contents);
+extern DECL_FUNC_PTR(krb5_copy_data);
+extern DECL_FUNC_PTR(krb5_free_creds);
+extern DECL_FUNC_PTR(krb5_build_principal);
+extern DECL_FUNC_PTR(krb5_get_renewed_creds);
+extern DECL_FUNC_PTR(krb5_free_addresses);
+extern DECL_FUNC_PTR(krb5_get_default_config_files);
+extern DECL_FUNC_PTR(krb5_free_config_files);
+extern DECL_FUNC_PTR(krb5_get_default_realm);
+extern DECL_FUNC_PTR(krb5_set_default_realm);
+extern DECL_FUNC_PTR(krb5_free_ticket);
+extern DECL_FUNC_PTR(krb5_decode_ticket);
+extern DECL_FUNC_PTR(krb5_get_host_realm);
+extern DECL_FUNC_PTR(krb5_free_host_realm);
+extern DECL_FUNC_PTR(krb5_c_random_make_octets);
+extern DECL_FUNC_PTR(krb5_free_default_realm);
+
+// Krb524 functions
+extern DECL_FUNC_PTR(krb524_init_ets);
+extern DECL_FUNC_PTR(krb524_convert_creds_kdc);
+
+// ComErr functions
+extern DECL_FUNC_PTR(com_err);
+extern DECL_FUNC_PTR(error_message);
+
+// Profile functions
+extern DECL_FUNC_PTR(profile_init);
+extern DECL_FUNC_PTR(profile_flush);
+extern DECL_FUNC_PTR(profile_release);
+extern DECL_FUNC_PTR(profile_get_subsection_names);
+extern DECL_FUNC_PTR(profile_free_list);
+extern DECL_FUNC_PTR(profile_get_string);
+extern DECL_FUNC_PTR(profile_get_values);
+extern DECL_FUNC_PTR(profile_get_relation_names);
+extern DECL_FUNC_PTR(profile_clear_relation);
+extern DECL_FUNC_PTR(profile_add_relation);
+extern DECL_FUNC_PTR(profile_update_relation);
+extern DECL_FUNC_PTR(profile_release_string);
+
+// Service functions
+extern DECL_FUNC_PTR(OpenSCManagerA);
+extern DECL_FUNC_PTR(OpenServiceA);
+extern DECL_FUNC_PTR(QueryServiceStatus);
+extern DECL_FUNC_PTR(CloseServiceHandle);
+extern DECL_FUNC_PTR(LsaNtStatusToWinError);
+
+// LSA Functions
+extern DECL_FUNC_PTR(LsaConnectUntrusted);
+extern DECL_FUNC_PTR(LsaLookupAuthenticationPackage);
+extern DECL_FUNC_PTR(LsaCallAuthenticationPackage);
+extern DECL_FUNC_PTR(LsaFreeReturnBuffer);
+extern DECL_FUNC_PTR(LsaGetLogonSessionData);
+
+// toolhelp functions
+TYPEDEF_FUNC(
+    HANDLE,
+    WINAPI,
+    CreateToolhelp32Snapshot,
+    (DWORD, DWORD)
+    );
+TYPEDEF_FUNC(
+    BOOL,
+    WINAPI,
+    Module32First,
+    (HANDLE, LPMODULEENTRY32)
+    );
+TYPEDEF_FUNC(
+    BOOL,
+    WINAPI,
+    Module32Next,
+    (HANDLE, LPMODULEENTRY32)
+    );
+
+// psapi functions
+TYPEDEF_FUNC(
+    DWORD,
+    WINAPI,
+    GetModuleFileNameExA,
+    (HANDLE, HMODULE, LPSTR, DWORD)
+    );
+
+TYPEDEF_FUNC(
+    BOOL,
+    WINAPI,
+    EnumProcessModules,
+    (HANDLE, HMODULE*, DWORD, LPDWORD)
+    );
+
+#define pGetModuleFileNameEx pGetModuleFileNameExA
+#define TOOLHELPDLL "kernel32.dll"
+#define PSAPIDLL "psapi.dll"
+
+// psapi functions
+extern DECL_FUNC_PTR(GetModuleFileNameExA);
+extern DECL_FUNC_PTR(EnumProcessModules);
+
+// toolhelp functions
+extern DECL_FUNC_PTR(CreateToolhelp32Snapshot);
+extern DECL_FUNC_PTR(Module32First);
+extern DECL_FUNC_PTR(Module32Next);
+
+khm_int32 init_imports(void);
+khm_int32 exit_imports(void);
+
+#endif
diff --git a/src/WINNT/netidmgr_plugin/help/Index.hhk b/src/WINNT/netidmgr_plugin/help/Index.hhk
new file mode 100644 (file)
index 0000000..c0ba08a
--- /dev/null
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<HTML>
+<HEAD>
+<meta name="GENERATOR" content="Microsoft&reg; HTML Help Workshop 4.1">
+<!-- Sitemap 1.0 -->
+</HEAD><BODY>
+<UL>
+</UL>
+</BODY></HTML>
diff --git a/src/WINNT/netidmgr_plugin/help/NTMakefile b/src/WINNT/netidmgr_plugin/help/NTMakefile
new file mode 100644 (file)
index 0000000..8d41e06
--- /dev/null
@@ -0,0 +1,37 @@
+#
+# Copyright (c) 2005 Massachusetts Institute of Technology
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation files
+# (the "Software"), to deal in the Software without restriction,
+# including without limitation the rights to use, copy, modify, merge,
+# publish, distribute, sublicense, and/or sell copies of the Software,
+# and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+RELDIR=WINNT\netidmgr_plugin
+!INCLUDE ..\..\..\config\NTMakefile.$(SYS_NAME)
+!INCLUDE ..\..\..\config\NTMakefile.version
+
+CHMFILE=$(DESTDIR)\root.client\usr\vice\etc\afsplhlp.chm
+
+install: $(CHMFILE)
+
+$(CHMFILE): afsplhlp.hhp
+       -hhc $**
+       $(COPY) afsplhlp.chm $(CHMFILE)
+
+clean::
+       $(DEL) $(CHMFILE)
\ No newline at end of file
diff --git a/src/WINNT/netidmgr_plugin/help/afsplhlp.h b/src/WINNT/netidmgr_plugin/help/afsplhlp.h
new file mode 100644 (file)
index 0000000..51738d4
--- /dev/null
@@ -0,0 +1,14 @@
+#define IDH_OBTAIN   3000
+#define IDH_CELL     3001
+#define IDH_REALM    3002
+#define IDH_METHOD   3003
+#define IDH_ADD      3004
+#define IDH_DELETE   3005
+#define IDH_TOKENLIST 3006
+#define IDH_SVCSTATUS 3007
+#define IDH_SVCSTOP   3008
+#define IDH_SVCSTART  3009
+#define IDH_SVCVERSION 3010
+#define IDH_SVCCOMPANY 3011
+#define IDH_SVCCPL     3012
+#define IDH_STARTAFSCREDS 3013
diff --git a/src/WINNT/netidmgr_plugin/help/afsplhlp.hhp b/src/WINNT/netidmgr_plugin/help/afsplhlp.hhp
new file mode 100644 (file)
index 0000000..5bc86f5
--- /dev/null
@@ -0,0 +1,29 @@
+[OPTIONS]
+Auto Index=Yes
+Compatibility=1.1 or later
+Compiled file=afsplhlp.chm
+Contents file=toc.hhc
+Default Window=MainHelpWnd
+Default topic=html/welcome.htm
+Display compile progress=No
+Index file=Index.hhk
+Language=0x409 English (United States)
+Title=OpenAFS Plugin for NetIDMgr
+
+[WINDOWS]
+MainHelpWnd="OpenAFS/NetIDMgr Help","toc.hhc","Index.hhk","html/welcome.htm","html/welcome.htm",,,,,0x42120,,0x384e,[271,372,593,566],0x830000,,,,,,0
+
+
+[ALIAS]
+
+[MAP]
+#include afsplhlp.h
+
+[TEXT POPUPS]
+afsplhlp.h
+popups_newcred.txt
+popups_cfg.txt
+
+[INFOTYPES]
+Category:Usage
+CategoryDesc:Usage instructions for OpenAFS/NetIDMgr
diff --git a/src/WINNT/netidmgr_plugin/help/html/afsplhlp.css b/src/WINNT/netidmgr_plugin/help/html/afsplhlp.css
new file mode 100644 (file)
index 0000000..f59706c
--- /dev/null
@@ -0,0 +1,73 @@
+BODY {
+   font-family:helvetica,sans-serif;
+   font-size:8pt; 
+   font-style:normal; 
+   background-color:white;
+   margin-top: 0;
+   margin-left: 0;
+   margin-right: 0;
+   }
+
+H1 {
+   font-size: 10pt;
+   border-bottom:1px solid black;
+   padding:5px;
+   background-color:#eeeeee;
+   }
+
+H2 {
+   }
+
+H3 {
+   font-size: 9pt;
+   border-bottom: 1px solid lightgrey;
+   padding: 5px;
+   }
+
+H4 {
+   font-size: 9pt;
+   font-style: italic;
+   border-bottom: 1px dashed lightgrey;
+   margin-left: 10px;
+   }
+
+P  {
+   margin-left: 5px;
+   margin-right: 5px;
+   }
+
+P.caption {
+   margin-left: 5px;
+   margin-right: 5px;
+   font-style: italic;
+}
+
+DIV.inline {
+   float: left;
+}
+
+DIV.sidebar {
+   float: right;
+   background-color:#ffffb9;
+   border: 1px solid #ffff00;
+}
+
+A.external {
+}
+
+A.mail {
+}
+
+IMG {
+   border: 0;
+}
+
+SPAN.pre {
+   font-family: courier;
+   font-weight: bold;
+}
+
+SPAN.title {
+   font-weight: bold;
+}
+
diff --git a/src/WINNT/netidmgr_plugin/help/html/bugs.htm b/src/WINNT/netidmgr_plugin/help/html/bugs.htm
new file mode 100644 (file)
index 0000000..214215c
--- /dev/null
@@ -0,0 +1,24 @@
+<html>
+<head>
+  <title>Reporting Bugs and Requesting Features</title>
+  <meta name="description" content="Reporting bugs and Requesting features">
+  <meta name="keywords" content="bugs,features">
+  <link rel="stylesheet" type="text/css" href="afsplhlp.css">
+</head>
+<body>
+
+<h1>Reporting Bugs and Requesting Features</h1>
+
+<p>If you experience a bug in the program, please send email to <a
+href="mailto:bugs@secure-endpoints.com"
+class="mail">bugs@secure-endpoints.com</a> and report it.  Please
+include as much information as possible to enable us to reproduce the
+problem.
+</p>
+
+<p>If there is a feature you would like to see in a future release, 
+please send email to the same address given above.
+</p>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/src/WINNT/netidmgr_plugin/help/html/config_service.htm b/src/WINNT/netidmgr_plugin/help/html/config_service.htm
new file mode 100644 (file)
index 0000000..93687d4
---