Have you peformed or are about to perform a massive user recertification? Or, have you peformed or are about to perform a domain merge? Or, do you sometimes get errors where renaming users via Adminp is not working? Or, are users? recertification dates and name changes not getting updated in the users ID file?
Have you had problems where the user does not get prompted for a user name change that has been completed by Adminp? Or, do you have problems where you have recertified a user from the Domino Directory but the user never gets their ID updated automatically?
So, what do you do? Re-Register the user?
Wrong! You should never re-register a user!
By re-registering your user, a new ID file is created and a new public key is given. Hence, they will never be able to access their encrypted memos and databases that have encryption enabled.
The public key stored in the ID File should be identical to the Public Key stored in the Person Document for that user. If the two public keys are not identical, then you will have problems somewhere along the track.
The Lotus Script code here allows you to extract the public key from the current active user ID. Then, you can optionally mail the key to a central point (user or mail-in-database).
You could insert this script, say, into the Post-Open event of all users mail files and only allow the script to execute once. By doing this, all users? public keys can be mailed to a central point on your server.
Once you have collected all of the users Public Keys from their ID File, you can then check the Public Keys against the Public Key entry in their Person Document.
Why do this?
Public keys often get out of sync for some unknown reason. I am sure that everyone has had at least one instance where user renames did not take. By doing this, you can be sure that every user ID is in synchronization with their public address book entry.
I would highly recommend performing this prior to a massive user recertification or domain merge. It will ensure that minimal or no problems with user IDs occur in the future.
To test this application, create a Lotus Script agent then copy the code below into the appropriate sections.
Nearly all these functions are undocumented by Lotus so I will not be able to provide you with much detail on the exact function that these API calls perform.
+++ Copy this code into the OPTIONS section of the script agent
Option Public Option Explicit
+++ Copy this code into the DECLARATIONS section of the script agent
Declare Function W32_SECKFMKfcTearDown Lib "nnotes.dll" Alias "SECKFMKfcTearDown" (Byval Memory As Long) As Integer Declare Function W32_SECKFMKfcSetup Lib "nnotes.dll" Alias "SECKFMKfcSetup" (Byval Memory As Long, Return1 As Long, Byval Flags As Long) As Integer Declare Function W32_SECKFMFileRead Lib "nnotes.dll" Alias "SECKFMFileRead" (Byval Memory As Long, Byval Memory2 As Long, Byval Flag1 As Long, Byval Flag2 As Long, Byval flag3 As Long) As Integer Declare Function W32_SECKFMAccess Lib "nnotes.dll" Alias "SECKFMAccess" (Byval Flag1 As Long, Byval Memory1 As Long, Byval Memory2 As Long, Byval Flag2 As Long) As Integer Declare Function W32_SECKFMGetIDConvertToHAC Lib "nnotes.dll" Alias "SECKFMGetIDConvertToHAC" (Byval Memory1 As Long, Byval Flags As Long, retHandle1 As Long, retHandle2 As Long) As Integer
Declare Function W32_Csetmem Lib "nnotes.dll" Alias "Csetmem" (Byval Dest As Long, Length As Long, Value As Long) As Long Declare Function W32_Cmovmem Lib "nnotes.dll" Alias "Cmovmem" (Byval source As Long, Dest As Long, Byval Length As Long) As Integer Declare Function W32_OSLockObject Lib "nnotes.dll" Alias "OSLockObject" (Byval handle As Long) As Long Declare Function W32_OSUnlockObject Lib "nnotes.dll" Alias "OSUnlockObject" (Byval handle As Long) As Long Declare Function W32_OSMemAlloc Lib "nnotes.dll" Alias "OSMemAlloc" (Byval BlkType As Long, swSize As Long, retHandle As Long) As Integer Declare Function W32_OSMemFree Lib "nnotes.dll" Alias "OSMemFree" (Byval Handle As Long) As Integer
+++ Copy this code over the top of the INITIALIZE routine of the script agent
Const SendTo = "Dennis Fry/Administrators/Acme" 'user name or mail-in-database to send the public key to
Dim session As NotesSession 'notes session - only used in the script when sending the public key Dim db As NotesDatabase 'current notes database - as above Dim doc As NotesDocument 'new notes document - as above Dim nnUserName As NotesName 'current user name Dim hKeyData As Long 'handle to some allocated memory, used to retrieve the public key Dim aKeyData As Long 'physical memory address to the allocated memory Dim hPublicKey As Long 'handle to the public key object Dim aPublicKey As Long 'physical memory address of the public key object Dim PublicKeyLength As Long 'length of the retrieved public key - in bytes Dim Memory As Long 'contains a pointer to a memory address or handle that is require to retrieve the public key Dim RetVal1 As Long 'unknown, undocumented - used with SECKFMfcSetup Dim lret As Long 'long return value from a function call Dim iret As Integer 'integer return value from a function call Dim Char As Long 'stores each ascii character of the public key, when retrieved Dim PublicKey As String 'string to store the public key from the Char value above Dim PosCounter As Integer 'counter for each character to translate into a valid string, from the public key
Set session = New NotesSession Set nnUserName = New NotesName(session.UserName)
'The ID file information retrieved, needs 608 bytes of data to store the information, so allocate 608 bytes of memory
iret = W32_OSMemAlloc(6145, 608, hKeyData) If iret <> 0 Then Msgbox "Unable to allocate memory...." Goto Clean_Up End If
'Key the physical memory address of the allocated memory, then clear the memory (fill with 0), all 608 bytes
aKeyData = W32_OSLockObject(hKeyData) lret = W32_Csetmem(aKeyData + 46, 608, 0)
'Extract the security key information from the current users ID file. Value parameters and offsets has been set by Lotusiret = W32_SECKFMKfcTearDown(aKeyData) iret = W32_SECKFMKfcSetup(aKeyData + 46, RetVal1, 0) iret = W32_SECKFMFileRead(aKeyData + 46, aKeyData + 99, 0, 0, 33)
'Extract 4 bytes (long data type) of memory from an offset of 46 from the security key information 'This value contains an object that stores the public key (probably in encrypted format ?)
iret = W32_Cmovmem(aKeyData + 46, Memory, 4)
'Access the security information that we require, then extract a memory handle to the public key and get the length of the public key
iret = W32_SECKFMAccess(49, Memory, aKeyData + 99, 0) iret = W32_SECKFMGetIDConvertToHAC (Memory, 3, hPublicKey, PublicKeyLength)
'The handle of the public key has been retrieved, so now get the physical memory address to the public key, so we can extract it in ASCII format
aPublicKey = W32_OSLockObject(hPublicKey)
'Extract each character of the public key, referencing the physical memory address, one byte at a time 'Each line of the public key (same as the format in the person document in the Domino Directory), is terminated with a null character 'As each character is read, populate the end-result public key string. Check for a null terminating character and insert this into the 'string as a carriage return & line feed (CRLF). Keep extracting the public key for the entire length of the key, as determined by 'the variable PublicKeyLength
For PosCounter = 0 To PublicKeyLength - 1 iret = W32_Cmovmem(PosCounter + aPublicKey, Char, 1) Char = Char And 255 If Char = 0 Then PublicKey = PublicKey & Chr$(10) & Chr$(13) Else PublicKey = PublicKey + Chr$(Char) End If Next
'The public key as now been extracted. Close the open memory objects of the public key and allocated memory
Call W32_OSUnLockObject(hPublicKey) Call W32_OSUnLockObject(hKeyData)
'Free up the resources used by the allocated memory. If the memory was not allocated earlier, exit the program
Clean_Up: If hKeyData <> 0 Then iret = W32_OSMemFree(hKeyData) Else End End If
'Display the public key for the current user
Msgbox PublicKey,,"Public Key for " & nnUserName.Abbreviated
'This code allows you to send the public key to a person or mail-in-database
Set db = session.CurrentDatabase Set doc = db.CreateDocument
doc.Form = "Memo" doc.SendTo = SendTo doc.Subject = nnUserName.Abbreviated & " - Public Key" doc.Body = PublicKey Call doc.Send(False)End Sub
This was first published in May 2001