Quantcast
Channel: Windows SDK Support Team Blog
Viewing all 27 articles
Browse latest View live

Launching an interactive process from Windows Service in Windows Vista and later

$
0
0

The first thing you should do about it is that, don't do it. There are many limitations, bad implications and restrictions involved into it.

In case, you are in a state that you cannot avoid launching an interactive process from Windows Service then you might want to read this article.

Launching an interactive application from a Windows service is different in Windows Vista

Introduction

To maintain isolation and provide rich user experience Windows uses sessions. When a user logs in a Terminal Services enabled computer a new session is created with each logon. Each session is associated with Logon LUID.

The interactive window station, Winsta0, is the only window station that can display a user interface or receive user input.

In Windows Vista and later Windows service run in a separate session.

In all the interactive sessions Winsta0 is created by default. A Window station acts as container to the desktop. Each session has at least one Window Station (default windows station "winsta0") and a Window station have three desktops

  • Default desktop
  • Screensaver desktop
  • Winlogon desktop

Name of the window station is case in-sensitive however name of desktops are case sensitive.

Windows station and desktop is provided to secure UI and GDI objects.  UI and GDI objects are associated with Windows station and desktops and Window station and desktops have DACLs associated with them. They are considered as securable objects in Windows.

Note:

  1. Windows station and desktop are secured. A user or a process running under that user's context can access them only if the user has got appropriate access rights to access it.
  2. Every session has its own isolated Window station and desktops. You cannot obtain handle of a Window station and subsequently of desktops of a session other than your session. Therefore you cannot modify the DACLs or security of the window station or desktops across session.

Effect of session on launching a process

A process is associated with the access token of a user. This access token is compared against securable objects DACLs when the process tries to access it.  There are 14 type of securable objects present in Windows for example Files, folders and registry keys. For a process it is must to have an access token which is derived from a user under whose context the process is launched.

There are three most effective ways to launch a process using Windows APIs.

1)      CreateProcess

a.       Access token is derived from the parent. The process is launched in the session of the parent and access the window station desktop of the parent by default.

b.      You can change the desktop accessed by this process by populating lpDesktop member of STARTUPINFO structure. Make sure that parent process has appropriate access to that window station and desktop and they are in the same session of the parent process.

2)      CreateProcessAsUser

a.       You need a primary access token to pass as the first parameter of this API.

b.      LogonUser API can be used to get the primary access token of a user. LogonUser expects credentials of the user in plain text.

3)      CreateProcessWithLogonW and CreateProcessWithTokenW

a.       The CreateProcessWithLogonW and CreateProcessWithTokenW functions are similar to the CreateProcessAsUser function, except that the caller does not need to call the LogonUser function to authenticate the user and get a token. CreateProcessWithLogonW cannot be called from Local System context. Therefore if you have a service running in Local System context you cannot use  CreateProcessWithLogonW.

Session information is kept in User's access token. A process gets a session depending on the token used to launch it. The session information of an access token can be changed.

Note: A process cannot change the session id of its own token.

Both 2nd and 3rd method requires a user to login in the local system. The newly created process's access token will be checked against the DACLs of Windows Station and desktop while it will try to attach itself to them.  Also, as mentioned above Windows create a session on each logon. While launching the process by using method 2 and 3 either you would need to create and specify windows station and desktop for lunching process or Windows by default will create a Window station and desktop

For 1st method, process is launched in the same session of parent process with same access token. By default this child process will have access to the Window station and desktop of the parent. If you are changing these two you would need to make sure that parent process have access to the new window station and desktop.

Process to launch the interactive process

Until Windows Server 2003 the services and the first logged on user used to run in the same session, Session 0. Therefore, the Window station and desktop of the first logged on user was shared by services running in the same session. Therefore services were able to obtain the handle of the user's desktop and modify its DACL.

Up to and including Windows 2003 you check the check box saying "Interact with desktop" in Properties dialog box of the Service and you can launch the process interactively.

With security enhancement in Windows Vista and later versions of Windows, services run in a separate session called Session 0. Now, in Session 0 a process can only get handle of Window station and desktop associated with session 0.

Let's categorize the process in two by two cases; we will discuss each of them. These cases are listed in decreasing order of feasibility.

1)       Your service is running in LocalSystem account context.

A.      You are willing to launch the application as currently interactively logged on user.

B.      You are willing to launch the application as some user other that interactively logged on user.

2)       Your service is running in any account other than LocalSystem account.

A.      You are willing to launch the application as currently interactively logged on user.

You are willing to launch the application as some user other that interactively logged on user.         

1.A. ) Your service is running in LocalSystem account and you are willing to launch the application as currently interactively logged on user.

This is how you do it:

Get the user token by calling

WTSQueryUserToken (WTSGetActiveConsoleSessionId (), &hToken) ;

Use this token in CreateProcessAsUser.

This token will have the right session ID of the interactive user. You will not have to change anything you are good to go.

1.B. ) Your service is running in LocalSystem account and you are willing to launch the application as some user other than interactively logged on user.

For an interactive application we need two essential things

1)      An access token with right session ID

a.       You need an access token of that user. You would need to call LogonUser to get the primary token. This call will create a new session and associate the session ID with token. Now, your token does not have the right Session ID. You can change it by calling SetTokenInformation. After this call you have the right session ID in the token.

2)      You need a Window station and desktop to associate with your application.

Newly created application will not have access right to the interactive session’s window station and desktop. This application cannot associate itself with interactive desktop.

Therefore, even though we have good token the launched process will not survive. It will be killed by Windows desktop manager because the desktop it is trying to access is not accessible to it.

You can change the permissions of the Window station and desktop. The only way to change the permission is to get the handle of the desktop. The process cannot obtain the handle of the desktop of session other than their session. This implies that service which is running in session 0 cannot obtain the handle of the desktop in the interactive session.

To workaround this you would need to perform following steps

a)      Launch a hidden temporary process as explained in step 1.A.

                                I.            Get the user token by calling WTSQueryUserToken (WTSGetActiveConsoleSessionId (), &hToken) ;

                              II.            Use this token in CreateProcessAsUser to launch the temporary process.

Call  CreateProcessWithLogonW from the temporary process to create the target application. CreateProcessWithLogonW saves you from explicitly modifying the DACL of the interactive desktop. However, you need the credentials of the target user to provide in this API.

2.A.) Your service is running in any other account and you are willing to launch the application as currently interactively logged on user.

You cannot call WTSQueryUserToken. This API can only be called from services running under LocalSystem account.

There is no definite way to do this because there is no legitimate way to obtain the logged on user's token with right Session ID. Here is what you should never, never and never do.

You would need to steal the access token of a process running on interactive user’s desktop. The best process to steal the access token would be Explorer provided only one interactive user is logged in. 

a)      Enumerate the process to get the handle of the Explorer.

b)      OpenProcessToken should give you the access token.
Note : The account under which your service is running must have appropriate privileges to call this API and get process token.

c)       Once you have the token call CreateProcessAsUser with this token. This token already have the right session Id.

2.B.) Your service is running in any account other than LocalSystem and you are willing to launch the application as some user other that interactively logged on user.

Same text goes again:: Here is what you should never, never and never do.

You would again need follow the technique we followed in 1.B . Launch a hidden application by performing

2.A.a, 2.A.b and 2.A.c

Once hidden application is launched follow 1.B.a- 1.B.f to launch the target application.

When interactive user log off

I have seen people saying that my application is running in a user's context which is not same as interactively logged in user, should my application be running when the interactive user logs off ?

When the user logs off, the system destroys the session associated with that user. Therefore the Windows stations and the desktops associated with that user will be destroyed. Even if your application is running in a different user's context it is attached to the interactive user's desktop.

All the applications running on the interactive desktop will be terminated. So is yours.

 However, you can expect a WM_QUERYENDSESSION and WM_ENDSISSION for your application.

Where is the code example ??

You got to write your own!!!

-Prateek


RDC and Custom Credential Providers

$
0
0

RDC and Custom Credential Providers

 

 

Issue: 

When you have your own custom credential provider (CP) for multifactor authentication (such as Biometric, password, Smartcard).

You do remote desktop connection (RDC) to connect to a client Vista machine where the client machine has installed this custom CP.   The issue is that you have to login twice for a Remote session.

In nutshell, you will get double logon when authenticating via RDP and using custom credential provider.  This behavior is by design.  You will not get double logon when using the Microsoft built-in credential providers, i.e. password and smartcard.

Reason:

The terminal Services does not support remote authentication with arbitrary credential types.   Only username/password or smart card credentials from the built-in Microsoft credential providers can be authenticated. 

Before Microsoft introduced Network Level Authentication (NLA), any malicious user could attempt multiple connections to a terminal server, and each connection attempt would use up lots of resources on the server. This attack may potentially make server run out of resources. In such case users would not connect anymore.  With NLA; it requires you to authenticate before big resources are used on the terminal server.  Also NLA can’t handle third party CPs, thus if NLA is enabled then custom CPs cannot be used with NLA, this is again intended. 

If the user connected with a non-Microsoft credential provider, then you will be prompted on the terminal server to enter credentials again (twice).  If NLA is not enabled, then despite entering using an unsupported credential provider on the client prior to the connection, the user will still be connected.  You will be left at the logon screen, where you can use any credential provider that is supported for local authentication.  There’s no way to avoid the two authentications when using unsupported credential providers.

Having said that, if you have your own credential providers and you try to do a remote desktop connection to a Vista box (having this Credential provider) then you would need to log-in twice. This is an expected behavior and it is by design and there is no legitimate way to avoid it.

Sandeep Sharma

Windows SDK - Microsoft

 

 

 

SetWindowHookEx API with WH_JOURNALRECORD. This API fails with access denied (Error 5).

$
0
0

A while ago I came across a problem in which  SetWindowHookEx API with WH_JOURNALRECORD was failing with Access denied on Windows Vista.

If you have the same problem you can do what I tried.

1)      Create and Embed an Application Manifest with Your Application.

o   In our case we would need manifest with <requestedExecutionLevellevel="requireAdministrator"uiAccess="true" />

2)      Authenticode Sign Your Application  You can follow following steps to create a certificate and sign your application. You will need a commercial certificate if you wish your application to be trusted on the target computer of a customer installing your application.The following procedures are provided as examples and are not intended to be strictly followed. For example, replace the test certificate's name with your certificate's name and ensure that you tailor the procedures to map to your specific CA and development environment.

                                             i.            Open Visual Studio Command prompt. Navigate to the folder which has the executable. For example: I am using the sample application you have sent. You should keep that sample application in trusted folder (Program Files).

                                           ii.            Generate the certificate makecert -r -pe -ss PrivateCertStore -n "CN=MyCertificate.com(Test)" MyCertificate.cer

                                          iii.            Sign the code. Applying a timestamp while signing your application will ensure that the application will continue to run after the validity period of the original certificate.Signtool sign /v /s PrivateCertStore /n  MyCertificate.com(Test) /t http://timestamp.verisign.com/scripts/timestamp.dll MyApplication.exe

                                         iv.            Install the Certificate. To install the test certificate

A.      Launch an elevated command window by right-clicking Command Prompt and selecting Run as administrator.

B.      In Command Prompt, type mmc.exe and press Enter.

C.      In the mmc, select File and then select Add/Remove Snap-in…

D.      In Add or Remove Snap-ins, select Certificates, click Add, and then click OK.

E.       In the Certificates snap-in dialog box, select Computer account and click Next.

F.       In Select Computer, select Local Computer, and then click OK.

G.     In Add or Remove Snap-ins, click OK.

H.      In the Certificates snap-in, and navigate to Trusted Root Certificate Authorities, right-click Certificates, select All Tasks, and then select Import…

I.        In the Certificate Import Wizard, import the test certificate, ContosoTest.cer.

 

3)      Run your application from trusted folders.

 

You might want to check the following document

Windows Vista Application Development Requirements for User Account Control Compatibility http://download.microsoft.com/download/5/6/a/56a0ed11-e073-42f9-932b-38acd478f46d/WindowsVistaUACDevReqs.doc

You would need to follow following steps elaborated in this white paper.

Step Six: Create and Embed an Application Manifest with Your Application (Page 63)

Step Eight: Authenticode Sign Your Application (Page 72)

 

By specifying UIAccess=”true” in the requestedPrivileges attribute, the application is stating a requirement to bypass UIPI restrictions on sending window messages across privilege levels. Windows Vista implements the following policy checks before starting an application with UIAccess privilege.

The application must have a digital signature that can be verified using a digital certificate that chains up to a trusted root in the local machine Trusted Root Certification Authorities certificate store.

The application must be installed in a local folder application directory that is writeable only by administrators, such as the Program Files directory. The allowed directories for UI automation applications are:

%ProgramFiles% and its subdirectories.

%WinDir% and its subdirectories, except a few subdirectories that are excluded because standard users have write access.

The %WinDir% subdirectories that are excluded subdirectories include:

 

\Debug

\PCHealth

\Registration

\System32\ccm

\System32\com

\System32\FxsTmp

\System32\Spool

\System32\Tasks

 

User Account Control: Only elevate UIAccess applications that are installed in secure locations

This setting is enabled by default. However, an administrator can disable it if there are situations where UIAccess applications (Accessible Technology) that must be launched from folders are not protected by administrator-only write access.

If the UI automation application that requests UIAccess meets the UIAccess setting requirements, then Windows Vista launches the application with the ability to bypass most of the UIPI restrictions. If the UI automation application does not meet the security restrictions, the application will be launched without UIAccess rights and can interact only with applications at the same or lower privilege level.

A process that is launched with UIAccess rights:

Has the ability to set the foreground window.

Can drive any application window using SendInput function.

Has read input for all integrity levels using low-level hooks, raw input, GetKeyState, GetAsyncKeyState, and GetKeyboardInput.

Can set journal hooks.

Uses AttachThreadInput to attach a thread to a higher integrity input queue

Possible uiAccess values

Value

Description

False

The application does not need to drive input to the user interface of another window on the desktop. Applications that are not providing accessibility should set this flag to false. Applications that are required to drive input to other windows on the desktop (on-screen keyboard, for example) should set this value to true. 

True

The application is allowed to bypass user interface control levels to drive input to higher privilege windows on the desktop. This setting should only be used for user interface Assistive Technology applications.

 -Prateek

Check membership of a group from user’s process access token

$
0
0

Question may be, I need to check If the user belong to a particular group or not? There are NetUser* APIs available in NetApi32.lib to list the groups a user belong to a group. You can actually check but then you will need to compare the string of the group you are interested to check and the list returned by the NetApi. Please see the sample available on NetUserGetGroups Function. This approach can be acceptable in some scenarios, but may not work in other.

In a domain environment, there are two domains A and B and have trust relationship in between them. An user of domain A, logged on to a machine in domain B. The application running as domainA\UserA, calls NetUserGetGroups to get the global groups of the user, for any purpose. Generally it should work fine and works fine, I have tested it on many environments, but this approach may fail as well. If the domain where the query should go, has not opened the port ( by firewall ) the API is going to use, then API will not able to get the list of groups for the user. To solve the problem, you need to open the port, which may not be possible because the management of DC on other end not want to do it at all. Now, How to solve it?

When the user logs on providing credentials, authenticated by the AD on DC successfully, gets the logon token, profile is loaded, desktop is created etc etc. The logon token has the information about the user, for what groups it belong to. When user launched any application, it will be launched by this logon token. So, the information about the groups is already within the process itself. You can check it with a tool called whoami (/all) in Windows directory. If we have any API to read this list then we don’t have to go to network again or use NetAPIs. GetTokenInformation Function can be used to list the groups and for other purposes. Is there an API to actually check if the user belong to a particular group? CheckTokenMembership Function can be used for this purpose. API does not look for the group by its name, but by SID. If we have the name, we can convert to SID and pass to CheckTokenMembership. Demo sample code will look like below--

#include<windows.h>

#include<Sddl.h>

#pragma comment(lib,"Advapi32.lib")

int main (int argc, CHAR * argv[])

{

BOOL bStatus;

BOOL bIsMember;

SID_NAME_USE sid_name_use;

DWORD dwDomainNameSize;

TCHAR tszDomainName [256];

PSID pSidToCheck;

DWORD cbsid=1024;

LPBYTE pPDC = NULL;

HANDLE hToken;

 

    if (argc != 2){

        printf("\nUSAGE: %ls grouptocheck\n\n", argv[0]);

        return 1;

    }

 

    bStatus = OpenProcessToken(OpenProcess(GENERIC_ALL, FALSE, GetCurrentProcessId()), GENERIC_ALL, &hToken);

    if (!bStatus){

        printf("OpenProcessToken failed: %u\n", GetLastError());

        return 1;

    }

 

    pSidToCheck = malloc (cbsid );

    dwDomainNameSize = sizeof(tszDomainName);

    bStatus = LookupAccountName(

        NULL,       // address of string for system name

        argv[1],      // address of string for account name

        pSidToCheck,      // address of security identifier

        &cbsid,      // address of size of security identifier

        tszDomainName,      // address of string for referenced domain

        &dwDomainNameSize,      // address of size of domain string

        &sid_name_use       // address of SID-type indicator

    );

 

    if (!bStatus){

        printf("LookupAccountName failed: %u\n", GetLastError());

        return 1;

    }

 

    bStatus = CheckTokenMembership(/*hToken*/ NULL, pSidToCheck, &bIsMember);

    if (!bStatus){

        printf("CheckTokenMembership failed: %u\n", GetLastError());

        return 1;

    }

 

    if (bIsMember)

        printf("The user is a member of the group.\n");

    else

        printf("The user is NOT a member of the group.\n");   

   

    return 0;

 

}

 

Nitin Dhawan

Windows SDK - Microsoft

Why does regedit.exe (or any other Microsoft program) crash when I try to create a remote thread into it using the CreateRemoteThread() API?

$
0
0

Question:

On Windows XP, I am starting regedit.exe in suspended mode and forcing it to call the LoadLibrary() API to load an external DLL by using the CreateRemoteThread() API.  After loading the DLL, when I try to resume the suspended thread, the application terminates.

Why is this form of extending an application not supported by Microsoft Developer Support? I thought the CreateRemoteThread API was supported.

Answer:

Microsoft PSS cannot not assist in any effort to troubleshoot or run code within Regedit (or any other Microsoft program) because it was not designed to do so.

Although the CreateRemoteThread API is supported by Microsoft Developer Support but creating a remote thread into another process is a poor way to build extensibility into an application. Extendable applications should have some form of an API, a scripting language, plug-in DLL support, etc.

Regedit.exe was not meant to be extended by any means—it has no API and no plug-in interface and therefore does not expect to run any code or threads which are not built into it.  Therefore, it also is not designed to run properly when another process calls the CreateRemoteThread to start a new thread within it.  It may run or it may not.  If it runs without a problem, it is only by coincidence. 

In fact, Microsoft strongly discourages using CreateRemoteThread/CreateRemoteThreadEx to start a thread in any process.  Its original purpose is to write debuggers and profilers.  Even with these tools, creating a thread in another process has a risk that the target process can fail.  Although the APIs themselves are documented and they will create a thread in another process (as documented), the effects the new thread has on the target process completely depend on what the target process and the new thread do – how they interact.  It’s the latter that causes the all the problems.

When you create a new thread in a process that doesn’t expect it, there are many interactions which can occur.  Here are some things that can happen:

a.    The new thread requires a stack in the application’s address space.  The application may want that memory for something else.  Perhaps the application will fail to make an allocation and then crash because it can’t recover from something that should “never” happen.

b.    It causes all the DllMain() functions of all the DLLs to get called for DLL_THREAD_ATTACH.  One of these could call an API which shouldn’t be called from DllMain(), causing a deadlock.

c.     It causes an extra DLL to get loaded somewhere in the process’s address space.  It could be that the DLL is loaded into a place where the app wants to allocate memory.  The DLL may load at its preferred address space or it may not—it depends on what is already in the process’s memory.

d.    The application may use the single-threaded CRT (C runtime library) which now could have multiple threads calling it.  Since the single-threaded CRT doesn’t set up the necessary data structures and locks to handle multiple threads, the CRT can crash.

e.     The injected code could simply have a bug and cause the application to crash.

f. The thread could cause a deadlock if it uses any synchronization objects that other parts of the application use.

g. Anti-malware and anti-virus programs may get triggered and kill the target process, especially if it is a known administrative tool that should be prevented from being hacked.

Microsoft’s efforts to make the platform more secure means we invest in technologies like DEP (data execution prevention) which happen to do more than simply prevent someone from executing data.  DEP also prevent exception handlers from executing in dynamically allocated code (because malware uses this technique), they may mark portions of the address space as no-access so that a DLL can’t be injected, address space layout randomization, required executable signing for kernel-mode modules, etc.  Microsoft will continue to improve the security of its products by similar technical means, so there is a greater chance in the future these techniques such as creating remote threads will fail more frequently.  (At the same time, a provision is made to allow debuggers to do what they need to do to be useful.)

Mahatab-ur-Rashid

Steps to sign a file using Signtool.exe

$
0
0

You may have a situation where you need to sign a file which may be an

a. .exe

b. .cab

c. .cat

d. .ocx

e. .dll

f. .stl

Using the CryptoAPI “signtool.exe”, the files can be digitally signed. Digitally signing a file essentially involves two steps.

1. Obtaining a code signing certificate that has an associated RSA private key for signing. The certificate could be issued to a user or computer or company or any other entity.

2. Running “signtool.exe” on the file and use that certificate for signing.

To test how this Works, we can use the MakeCert utility that comes in with the Windows SDK or the Platform SDK installer. Makecert utility generates X.509 certificates for testing purposes only. It creates a public and private key pair for digital signatures and stores it in a certificate file. For more information on Makecert see the MSDN link http://msdn.microsoft.com/en-us/library/bfsktky3(VS.80).aspx.

Say we use the following command to create a certificate file.

makecert.exe -r -pe -ss MY -sky exchange -n CN=MyPrivateCert CodeSign.cer

The parameters are explained in Figure 1 below.

clip_image002

Figure 1: Meaning of parameters passed with makecert.exe

Once you créate the .cer file,you need to add it to the "Trusted Root Certification Authorities" store of Local Computer in MMC certificates snap-in for establishing the trust,if the code is verifying the certificate chain on the verification side. If the certificate is issued by a commercial CA such as VeriSign or Thawte, this step is not needed.

To install the certificate at the "Trusted Root Certification Authorities" store see the section below saying “How to install a certificate at the Trusted Root Certification Authorities store on your computer account"

To sign the file, say an EXE use the command

Signtool sign /v /s MY /n MyPrivateCert /t http://timestamp.verisign.com/scripts/timstamp.dll FileToSign.exe

If this succeeds then it will give as output

Number of files successfully Signed: 1

Number of warnings: 0

Number of errors: 0

The parameters are explained in Figure 2 below.

clip_image004

Figure 2: Meaning of parameters passed with Signtool.exe

If you import a code signing certificate to a PFX file, you can use the following command to sign a file.

Signtool sign /f <PFX file name> /p <Password> FileToSign.exe

where /p specifies the password to use when opening the PFX file.

How to get a code signing certificate from Microsoft Certificate Services

If you have a server operating system such as Windows Server 2008 or 2003 you can install IIS and Microsoft Certificate Services component.

To install Microsoft Certificate Services component go to Control Panel->Add or Remove Programs->Add/Remove Window Components and select “Certificate Services”.

Once “Certificate Services” are installed you can browse to the enrolment page as shown in Figure 3 on the server with the URL http://Win2kServer/certsrv, where “Win2kServer” is the machine name.

clip_image006

Figure 3: The Certificate Enrolment page on the server.

· Click on the "Request a certificate" link.

· Click on the "advanced certificate request" link.

· Click on "Create and submit a request to this CA".

· In Advanced Certificate Request fill out fields such as the "Name", Type of certificate needed which should be a “Code Signing certificate”.

· Select "Mark key as exportable" as shown in Figure 4 below.

clip_image008

Figure 4: The Advanced Certificate Request page.

Clicking on the “Submit >” button at the bottom of the “Advanced Certificate Request” page creates the certificate but you need to issue the certificate from the Certificate Authority snap-in from MMC as shown in Figure 5 below.

clip_image010

Figure 5: The Certificate Authority snap-in from MMC. You need to issue the certificate under pending request.

Once the certificate is issued you can again browse to the enrolment page on the server and click at “View the status of a pending certificate request”. Select the certificate and install the certificate.

Once installed you can view this certificate under the Personal store from the Certificate snap-in at MMC. You can also import the certificate to a PFX file with the private key and type and confirm a password.

How to install a certificate at the Trusted Root Certification Authorities store on your computer account

To add the certificate, go to Start->Run ->MMC <Enter>.

When the console window comes up, select File -> Add/ Remove Sanp in…

From the “Add or Remove Snap-ins” window select “Certificates” and click at “Add >”. Select “Computer Account” and then click at “Next”.

Select “Local Computer” and click at “Finish”.

clip_image012

Figure 6: MMC console showing how to add the “Certificates” snap-ins for the Local computer.

Open “Trusted Root Certification Authorities” store at the left pane and click at “Certificates”, shown in Figure 7. Then right click at the right window pane and select “All Task -> Import”.

Import the above CodeSign.cerfile that you created and install it.

clip_image014

Figure 7: Certificate snap-in showing the “Trusted Root Certification Authorities -> Certificates” store.

 

Shamik Misra

Windows SDK

Opps!!! System.Security.Cryptography.CryptographicException: The system cannot find the file specified.

$
0
0

If you are creating the cryptographic keys on the user's profile directory you may get a cryptographic exception saying: "CryptographicException: The system cannot find the file specified".

The stack trace looks like:

System.Security.Cryptography.CryptographicException: The system cannot find the file specified.

at System.Security.Cryptography.Utils.CreateProvHandle(CspParameters parameters, Boolean randomKeyContainer)

at System.Security.Cryptography.Utils.GetKeyPairHelper(...)

at System.Security.Cryptography.RSACryptoServiceProvider.GetKeyPair()

On most cases the reason for this exception is that RSACryptoServiceProvider calls into CryptAcquireContext.

CryptAcquireContext will create a file for storing keys in the user’s profile. If the user’s profile is not loaded, CryptAcquireContext fails with ERROR_FILE_NOT_FOUND.

What you can do is; you instantiate the RSACryptoServiceProvider class in the following way:

   1: CspParameters cspParams = new CspParameters(); 
   2:  
   3: cspParams.Flags = CspProviderFlags.UseMachineKeyStore;
   4:  
   5: RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(cspParams);

Doing this the cryptographic keys will be created in the MachineKeys folder, which every user has access. However the user that created this key has the only access to this file, unless this user gives others explicit access to this crypto key.

Calling RSACryptoServiceProvider with the CspProviderFlags.UseMachineKeyStore flag is same as calling CryptAcquireContext with the CRYPT_MACHINE_KEYSET flag.

For more information please visit the section "Using the CRYPT_MACHINE_KEYSET flag" at http://support.microsoft.com/?id=238187.

For a greater and detailed reference you can see the well-known blog from "Decrypt my World" by Alex at the link http://blogs.msdn.com/alejacma/archive/2007/12/03/rsacryptoserviceprovider-fails-when-used-with-asp-net.aspx.

 

Shamik Misra

Windows SDK

Web Service can’t start the Windows Service

$
0
0

Working with Windows Service and Web Service together is nothing less than fun, especially when you are not an ASP.NET expert. Like many native developers I have my own challenges with words like managed, web service and web applications!

I was debugging a production down. My customer had a Web application which was communicating with a Windows Service. Whenever the web application use to start it use to check if Windows Service is running, if not it would attempt to start the Windows Service.  This web application was failing to start the Windows Service. Web applications have their own way of reporting the failure, we got back Cannot open the service control manager on computer “.”

This web application use to work fine when a domain administrator or a user who is administrator on the IIS server launches the web application. It was domain users who were getting these errors.

We later figured out that the Web application is written in C# and it was using .Net 2.0. Also, it was using integrated authentication  (Windows Authentication) this means that the identity in which the user is logged in on the client computer (where the Internet Explorer is running) will be delegated to the ASP.NET application to do any kind of operation. Also, .NET 2.0 has impersonation true by default. The above information is important it tell that it is actually domain user who will attempt to start the Windows Service.

Windows service is a securable object in Windows. By default, only Administrators can start and stop a Windows Service.  It is determine by the DACLs present on the service.  This pretty much tells that why the domain users were not able to start the service.

I printed the DACL of a Windows Service

C:\Windows\system32>sc sdshow Service1

D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLOCRRC;;;IU)(A;;CCLCSWLOCRRC;;;SU)S:(AU;FA;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;WD)

The heighted ACE is grants access to the administrators. You can notice by default there is no ACE present for the authenticated user.  The DACL of the service is given while the service is being created. During installation you can provide a custom DACL to your service depending on your needs.

Follow these steps to change the DACL of a Windows Service such that it grants permissions to authenticated users as well. Change the name of the service from Service1 to your service.

1)       Login the Server as Administrator and run CMD.
2)       SC SDSHOW Service1 > OldSDofService1.txt
3)      The output in the  OldSDofService1.txt should look like :  D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLOCRRC;;;IU)(A;;CCLCSWLOCRRC;;;SU)
4)      Change it to D:(A;;CCLCRPRC;;;AU)(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLOCRRC;;;IU)(A;;CCLCSWLOCRRC;;;SU) and save it to NewSDofService1.txt. Highlighted text shows the changed part of SDDL.
5)      In the command prompt run SC SDSET Service1 D:(A;;CCLCRPRC;;;AU)(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLOCRRC;;;IU)(A;;CCLCSWLOCRRC;;;SU)
6)      Do SC SDSHOW Service1 and compare the output, you should see the newly set string.

Once new DACLs are applied authenticated users can start and stop the windows service. That means a web application which has an identity of domain user (authenticated user) can operate on the Windows Service.

This problem is not related with code of the Web Application and Windows Service. It is more dictated by the environment. Access on a Windows Service is more to do with setup of Active Directory and policies and permissions in the domain.
We cannot foresee this problem and there for cannot fix it in the code. However, it is possible to modify the DACL of the SCM during installation; so if you are certain about who all are going to access your service you can provide appropriate DACLs.

I did not discuss about deciphering the security descriptor string. If you have difficulties you can refer to Security Descriptor Definition Language 

-Prateek


I lost the “Security” tab of offline files synced by Sync Centre !!

$
0
0

In Windows Vista and later there is a cool feature of making network shared files available offline and maintaining the synchronization through a newly added component called Sync Centre.  You may find more information about it here:  Explore the features: Sync Center.

You might have a functionality where you would like to know the security permissions of a file present locally on the box.  Functionality like programmatically you enumerate all those users who have read/write permissions on a folder or a file. 

Now what would happen if you wish to have the similar functionality  where you check the security permissions for an offline files synced by Sync Center when the network is not available?

If you go to properties of the offline file/folder you could see that when remote machine is disconnected from network then you are not able to see the security tab as shown in screen shots below.

clip_image001

clip_image002

Eventually you are *not* able to get the security permissions programmatically.  There are certain set of methods listed in Offline Files API, but it does not have any interface to provide the security permission information we are looking for.

The reason for the unavailability of this information is because it is not exposed.  Why?, the reason for this is to maintain consistency between the effective security permissions with respect to the actual remote server and the Sync Center.  When server is offline then there is very possibility that the administrator may change the security permissions.  The actual ACL’s are only stored on the server end, therefore, can only be shown in a user interface when connected to the server.  Internally the Sync center actually store the effective permissions in the Offline Files metadata and access check is enforced when offline. 

Hence the file system APIs (like GetFileSecurity , GetSecurityInfo, GetNamedSecurityInfo, GetKernelObjectSecurity etc.) for querying and setting security on a file will fail with either STATUS_ONLY_IF_CONNECTED or STATUS_NOT_SUPPORTED.  Still if you would like to know if a given user has READ access to a give file, the application could attempt to open the file with READ access in the user’s security context but this is not a scalable workaround.

I hope you will find this information useful !!

Sandeep Sharma

Microsoft - WinSDK team

Dealing with Administrator and standard user’s context

$
0
0

With introduction of UAC, I often get two questions for Windows Vista and later.

1)      How to launch an application in the Administrative context from an application which is running in standard user’s context?

2)      How to launch application in standard user’s context from an application which is running in administrative context?

 

The first question has been discussed in details on multiple places. The following description clearly talks about the methodologies which can be used and their consequences.

 

Spawning Interactive Child Processes

There is no published API for applications to spawn an arbitrary program as an adminstrator like Windows Explorer’s “Run as Administrator” context menu.  The overall UAC design philosophy is that admin and installation applications need to be detected by the program launch mechanism rather than individually started as elevated or not by the calling program.  This frees the caller from having to know which processes to run elevated and which to run as standard users.

 

CreateProcess() and CreateProcessWithLogonW do not have new flags to launch the child process as elevated.  Internally, CreateProcess() checks whether the target application requires elevation by looking for a manifest, determining if it is an installer, or if it has an app compat shim.  If CreateProcess() determines the target application requires elevation, it simply fails with ERROR_ELEVATION_REQUIRED(740).  It will not contact the AIS to perform the elevation prompt or run the app.  If CreateProcess() determines the application doesn’t require elevation, it will spawn it as a new process.

 

Likewise, it would seem reasonable to attempt this with the following code, but it doesn’t work:

OpenProcessToken (GetCurrentProcess, …)

GetTokenInformation (TokenLinkedToken)

CreateProcessWithTokenW(hLinkedToken, …)

 

To programmatically launch a child process as an elevated process, two things must occur: first, the executable of the child process needs to be identified as needing elevation, and second, the parent process needs to use ShellExecute() or ShellExecuteEx().  Applications that are designed to perform admin tasks should be marked with a signed application manifest that sets the requestedExecutionLevel to “requireAdministrator”.  See page 60-71 of “Windows Vista Application Development Requirements for User Account Control Compatibility” in the reading list below.  Then, when an application uses ShellExecute(), the following sequence of events occurs:

 

Parent Process is Standard User

The Windows Vista standard user launch path is similar to the Windows XP launch path, but includes some modifications.

 

1)      Application calls ShellExecute() which calls CreateProcess().

2)      CreateProcess() calls AppCompat, Fusion, and Installer Detection to assess if the application requires elevation. The executable is then inspected to determine its requestedExecutionLevel, which is stored in the executable's application manifest. The AppCompat database stores information for an application's application compatibility fix entries. Installer Detection detects setup executables.

3)      CreateProcess() returns a Win32 error code stating ERROR_ELEVATION_REQUIRED.

4)      ShellExecute() looks specifically for this new error and, upon receiving it, calls across to the Application Information service (AIS) to attempt the elevated launch.

 

Parent Process is  an Elevated User

The Windows Vista elevated launch path is a new Windows launch path.

 

5)      Application calls ShellExecute() which calls the AIS.

6)      AIS receives the call from ShellExecute() and re-evaluates the requested execution level and Group Policy to determine if the elevation is allowed and to define the elevation user experience.

7)      If the requested execution level requires elevation, the service launches the elevation prompt on the caller’s interactive desktop (based on Group Policy), using the HWND passed in from ShellExecute().

8)      After the user has given consent or valid credentials, AIS will retrieve the corresponding access token associated with the appropriate user, if necessary. For example, an application requesting a requestedExecutionLevel of highestAvailable will retrieve different access tokens for a user that is only a member of the Backup Operators group than for a member of the local Administrators group.

9)      AIS re-issues a CreateProcessAsUser() call, supplying the administrator access token and specifying the caller’s interactive desktop.

 

Spawning Non-interactive Child Processes

One cannot launch non-interactive child processes as another user with FULL access token from a parent process that is started with LUA access token. It may seem reasonable to attempt the following code to launch a process with FULL access token from a process started with LUA access token, but, it doesn't work.

 

LogonUser(member of local Administrators), ...

          LOGON32_LOGON_BATCH, .., &hToken)

ImpersonateLoggedOnUser(&hToken)

CreateProcessWithTokenW(hToken, ...)

 

If one needs to launch non-interactive processes, they can do only from parent processes that are started with FULL access token such as LocalSystem service or service running under an account that is member of Administrators group. Non-interactive software installations as Administrator may use methods like SMS deployment.

 

For question 2, it becomes difficulty to decrease the privileges of the child process. In earlier case we have found that an application must use manifest to let operating system know the level of execution required. Remember there are three levels which can be defined in an application manifest.

 

Requested Execution Levels

Possible requested execution level values

Value

Description

Comment

asInvoker

The application runs with the same access token as the parent process.

Recommended for standard user applications. Do refractoring with internal elevation points, as per the guidance provided earlier in this document.

highestAvailable

The application runs with the highest privileges the current user can obtain.

Recommended for mixed-mode applications. Plan to refractor the application in a future release.

requireAdministrator

The application runs only for administrators and requires that the application be launched with the full access token of an administrator.

Recommended for administrator only applications. Internal elevation points are not needed. The application is already running elevated.

 

If the caller is an Administrator you will not be able to use any of the execution level to ensure that the child application launched uses standard user token.

 

In this case one reasonable approach would be with following code and it should work.

OpenProcessToken (GetCurrentProcess, …)

GetTokenInformation (TokenLinkedToken)

CreateProcessWithTokenW(hLinkedToken, …)

 

If you are running as in interactive administrative context you can use following approach.

See the following sample, this sample if launched as an administrator will launch Nodepad.exe in a standard user’ context. To paunch this sample as an administrator you would need to manifest it with requireAdministrator execution level:

 

#include <Windows.h>

 

#pragma comment (lib, "advapi32.lib")

 

void CreateLowProcess( HANDLE hLowPrivToken, WCHAR *wszProcessName);

HANDLE GetLinkedToken(HANDLE hToken) ;

 

int _tmain(int argc, _TCHAR* argv[])

{

                BOOL                  fRet;

                HANDLE                hToken        = NULL;

                HANDLE                hNewToken     = NULL;

                TOKEN_LINKED_TOKEN tlt = {0};

 

                // Notepad is used as an example

                fRet = OpenProcessToken(GetCurrentProcess(),

                                TOKEN_DUPLICATE |

                                TOKEN_ADJUST_DEFAULT |

                                TOKEN_QUERY |

                                TOKEN_ASSIGN_PRIMARY,

                                &hToken);

 

                if (!fRet) {

                                return 0;;

                }

 

                WCHAR wszProcessName[MAX_PATH] =

                                L"C:\\Windows\\System32\\Notepad.exe";

                HANDLE hLowPrivilage = GetLinkedToken(hToken);

 

                if(NULL != hLowPrivilage) {

                                CreateLowProcess(hLowPrivilage,wszProcessName);

                }

                return 0;

}

 

HANDLE GetLinkedToken(HANDLE hToken)

{             

 

                HANDLE hProcessToken = NULL;

                HANDLE hLinkedToken = NULL;

                DWORD et = (0);

                DWORD dwReturnLength;

                if (0 == GetTokenInformation(hToken,TokenElevationType, &et, sizeof(et), &dwReturnLength ))

                {  // return of zero indicates an error

                                return NULL;

                }

                else

                {              // success

                                switch (et)

                                {

                                case TokenElevationTypeDefault:

                                                hLinkedToken = NULL;

                                                break;

                                case TokenElevationTypeLimited:

                                                {

                                                                hLinkedToken = NULL;

                                                                break;

                                                }

                                case TokenElevationTypeFull:

                                                {

                                                                TOKEN_LINKED_TOKEN linkedToken;

                                                                DWORD dwLength;

                                                                linkedToken.LinkedToken = 0;

                                                                int iRet = GetTokenInformation(hToken, TokenLinkedToken, &linkedToken, sizeof ( linkedToken), &dwLength);

                                                                if (0 == iRet)

                                                                {

                                                                                hLinkedToken = NULL;

                                                                }

                                                                else

                                                                {

                                                                                hLinkedToken = linkedToken.LinkedToken;

                                                                }

                                                }

                                } // switch (et)

                }

 

                if (hProcessToken)

                {

                                CloseHandle(hProcessToken);

                }

                return hLinkedToken;

}             

 

void CreateLowProcess( HANDLE hLowPrivToken, WCHAR *wszProcessName)

{

                PROCESS_INFORMATION   ProcInfo      = {0};

                STARTUPINFO           StartupInfo   = {0};

                DWORD dwError = 0;

                DWORD dwLength = 0;

                BOOL fRet = 0;

 

 

                fRet  = CreateProcessAsUser(hLowPrivToken,

                                NULL,

                                wszProcessName,

                                NULL,

                                NULL,

                                FALSE,

                                0,

                                NULL,

                                NULL,

                                &StartupInfo,

                                &ProcInfo);

 

                if (0==fRet) {

                                return;

                }

 

                WaitForSingleObject(ProcInfo.hProcess,INFINITE);

 

                if (ProcInfo.hProcess != NULL) {

                                CloseHandle(ProcInfo.hProcess);

                }

 

                if (ProcInfo.hThread != NULL) {

                                CloseHandle(ProcInfo.hThread);

                }

                return ;

}

If you are not able to get TokenLinkedToken token, most likely the process is not interactive. Perhaps it has got token from following code sequence

LogonUser(member of local Administrators), ...

          LOGON32_LOGON_BATCH, .., &hToken)

ImpersonateLoggedOnUser(&hToken)

CreateProcessWithTokenW(hToken, ...)

 

In this case you would need to use CreateRestrictedToken to create a low privileged token from the administrative token of the parent. You would need to specifically strip the privileges you don’t need.  

 

-Prateek

 

Don't forget Integrity Levels when troubleshooting "Access Denied" errors

$
0
0

Anyone who has used Windows has encountered the dreaded "Access Denied" error.  (AKA error code 5 or 0x5). This error typically implies you can't do something like open or save a file.  The error implies that you have encountered some type of security issue.

In the past, an "Access Denied" issue came down to 2 things in Windows:

  1. Token
  2. DACL (Discretionary Access Control List)

A token represented a user and Windows compared it to the DACL of the secured object that the user was accessing.  Windows was answering the basic question, "Does the user have the requested access to the secured object?".  Once you dig into these 2 items, explaining an "Access Denied" error is easy but understanding whether this is the expected result is much more difficult.  (I may discuss this further in a future BLOG post).

Lately, solving "Access Denied" issues have become more complex due to a new security feature which was introduced in many years ago (Windows VISTA), Mandatory Integrity Control (Integrity Levels).  The purpose of Integrity Levels was to add an extra security check where a user running untrustworthy code is attempting to do something malicious.  See the following for more information:

https://msdn.microsoft.com/en-us/library/windows/desktop/bb648648(v=vs.85).aspx

There are 4 levels of integrity in Windows.  Different users in Windows have a different default integrity level.

  • Anonymous - Anonymous User
  • Low
  • Medium - Normal User
  • High - Elevated User (Administrator)
  • System - LocalSystem

The best example of Integrity Level Usage is Internet Explorer's Protected Mode (See https://msdn.microsoft.com/en-us/library/bb250462%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396 ) Basically, Internet Explorer is running in a Low Integrity Level.  What this means is that even though a user may have the appropriate access to a file, the file cannot be accessed from Internet Explorer.  I mentioned above that an access check was based on the system comparing the user's token with the secured object's DACL.  Well, we need to check one more thing, the integrity level of the user's token and what level can access the secured object.  A user can only access objects that have the same or lower integrity level.  In the case of IE, most files and directories in Windows have a medium or higher integrity level and since IE Is running at a low integrity level, any code running in IE will not be able to access any files or directories even if the user has the appropriate permissions to the file or directory.  The above article goes into details on finding the default low integrity level directory which IE can access.  Integrity levels also impact the registry as well.

The integrity level for the user is stored in the token.  The integrity level for a secured object is actually stored in the SACL but the ACEs are not System Aces but they are called System Mandatory Label ACEs.  The Access Check is still the same but there is an additional check that needs to be made from the token and from the Security Descriptor.

So the next time you are dealing with an "Access Denied" error, do not forget to check the integrity levels of the user and the secured object.  You'll save yourself a lot of time.

Follow us on Twitter, www.twitter.com/WindowsSDK.

 

 

 

Windows Hotfixes for October 2015

$
0
0

Jeff here from the Windows SDK team. Here is the list of October 2015 Hotfixes

[Drum roll, please...]

KB3030736   "550 The process cannot access the file" error when you try to download a file in Windows

KB3044546   An updated reservation may disappear on a DHCP failover cluster in Windows Server 2012 or Windows Server 2012 R2

KB3049591   Transparent areas are printed as black when you use a v4 XPS printer driver in Windows

KB3053667   Users can't connect to virtual machines that are running Windows 8.1 or Windows Server 2012 R2 by remote desktop

KB3077354   Computer freezes when WFP leaks nonpaged pool memory in Windows Server 2012 R2 or Windows Server 2012

KB3084093   Child nodes under protected OU are deleted in Windows Server 2012 R2

KB3084426   System becomes unresponsive when file system minifilter drivers are installed in Windows 8 or Windows Server 2012

KB3084787   Event ID 4102 when DFS Replication cloning fails on a Windows Server 2012 R2-based cluster

KB3084953   OOBE crashes when you enter SIM card PIN in Windows 8.1

KB3084956   You can’t log on to a domain-joined computer in Windows 8 or Windows Server 2012

KB3084983   SetOptions or GetOptions method doesn't work for PRINTER_PROPERTY features in Windows

KB3086644   System freezes after you start a backup task for virtual machines in Windows Server 2012 R2

KB3090322   Space doesn't regenerate upon reallocation in Windows Server 2012 R2

KB3090973   Reenlist can't be called when SQL Server receives transaction outcome from MSDTC in Windows Server 2012 R2

KB3091057   Cluster validation fails in the "Validate Simultaneous Failover" test in a Windows Server 2012 R2-based failover cluster

KB3091061   Update to add CSVFS tracing for performance issues during backup operations in Windows Server 2012 R2

KB3091342   Computer crashes after you install update 3000850 in Windows 8.1

KB3091402   Site-to-site VPN goes down when you set a VNet-to-VNet connection in Azure in Windows 8.1 or Windows Server 2012 R2

KB3091403   High CPU usage for 12 seconds on a multiple-network-adapters computer in Windows Server 2012 R2 or Windows Server 2012

KB3092002   Set-Acl cmdlet fails although delegated admins have "Change Permissions" enabled in Windows Server 2012 R2

KB3092003   Page loads repeatedly and authentication fails when users use MFA in Windows Server 2012 R2 AD FS

KB3092005   Group Policy settings are set back to factory settings in GPMC in Windows Server 2012 R2

KB3092006   Subfolders disappear from FSRM console after you rename the root folder in Windows Server 2012 R2 or Windows Server 2012

KB3092695   Licensing report file is corrupted in Windows Server 2012 R2 RDS environments for large report files

KB3093550   All ScriptProperty members are invoked when you run the Add-Member PowerShell command in Windows 8.1

KB3093571   Update to replicate multiple VM groups and VMs that use shared VHDs in Windows Server 2012 R2 or Windows Server 2012

KB3093803   Error 0x800704C9 occurs when you try to copy file to NFS share in Windows 8 or Windows Server 2012

KB3093899   VMs that run on CSVs fail if DCM can't query volumes in Windows Server 2012 R2

KB3093900   0x50 Stop error and users can't access documents on shared folders or home folders in Windows Server 2012 R2

KB3094197   Files aren't fully optimized and a deduplication cache lock contention issue occurs in Windows Server 2012 R2

KB3094199   Application module can't receive correct process status after security update 3045999 is installed in Windows

KB3094202   Directory listing fails when sharing violations occur on Windows Server 2012 R2 or Windows Server 2012-based NFS server

KB3094446   Authentication through proxy fails in Windows Server 2012 or Windows Server 2008 R2 SP1

KB3095308   VMs may not get additional memory although they're set to use Dynamic Memory in Windows Server 2012 R2

KB3095319   You receive an error message when you use GPMC to manage audit policies in Windows 8.1 or Windows Server 2012 R2

KB3095663   VSS_E_PROVIDER_VETO error occurs when you restore a LUN from backup in Windows Server 2012 R2

KB3095711   Update to support LTO-7 tape drives in Windows Server 2012 R2 and Windows Server 2012

KB3095737   Azure Backup takes a long time to back up data with a guest OS that's running Windows Server 2012

Happy patching…

/Jeff

Follow us on Twitter, www.twitter.com/WindowsSDK.

 

Virtual Desktop Switching in Windows 10

$
0
0

 

Windows 10 introduces a new concept (for Windows anyway) called Virtual Desktops.  Currently, the guidance for this on MSDN states:

The user can group a collection of windows together to create a virtual desktop. Every window is considered to be part of a virtual desktop. When one virtual desktop is hidden, all of the windows associated with it are also hidden. This enables the user to create multiple working environments and to be able to switch between them. Similarly, when a virtual desktop is selected to be active, the windows associated with that virtual desktop are displayed on the screen.

To support this concept, applications should avoid automatically switching the user from one virtual desktop to another. Only the user should instigate that change. In order to support this, newly created windows should appear on the currently active virtual desktop. In addition, if an application can reuse currently active windows, it should only reuse windows if they are on the currently active virtual desktop. Otherwise, a new window should be created.

That’s good advice as it makes for the best user experience in most cases and as a developer lets you ignore virtual desktops altogether in most simple applications; however, if you have an application or scenario that wants to do something such as always stay on top even when the user changes virtual desktops, what can you do?

IVirtualDesktopManager

To go along with the addition of virtual desktops in Windows 10, a new shell interface was introduced called IVirtualDesktopManager.  It only has three functions, but those allow you to do many things with virtual desktops and your own application.  Attempting to say move a window to another virtual desktop with these functions will not work for windows that your process doesn’t own.  As this isn’t a scenario that should be common or desired behavior for most applications, there’s isn’t a notification that you can subscribe to so that you know that your application window’s virtual desktop is no longer visible or that your application window has been moved to a new virtual desktop.  However, if your window has focus when the user switches to another virtual desktop, you will be told that you’ve lost focus.

IsWindowOnCurrentVirtualDesktop will tell you if your window is on the current virtual desktop.  GetWindowDesktopId will give you the ID of the desktop the specified window is on.  MoveWindowToDesktop will allow you to move a specified window to a specified desktop.

But how do you know what the current desktop ID is if you don’t have any windows on the current desktop?  That one turns out to be pretty simple.  If you create a new window with no parent, it will be placed on the current virtual desktop.

Demonstration

Putting all of the above together, here’s a straightforward C# WinForms app as an example of an always on top window that can move itself between Virtual Desktops (csproj attached at the end):

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace VirtualDesktopSwitch
{
    /// <summary>
    /// Example form
    /// </summary>
    public partial class VDExampleWindow : Form
    {
        public VDExampleWindow()
        {
            InitializeComponent();
        }
        private VirtualDesktopManager vdm;
        private void VDExampleWindow_Load(object sender, EventArgs e)
        {
            //Create IVirtualDesktopManager on load
            vdm = new VirtualDesktopManager();
        }

        private void label1_Click(object sender, EventArgs e)
        {
            //Show details on click
            MessageBox.Show("Virtual Desktop ID: " + vdm.GetWindowDesktopId(Handle).ToString("X") + Environment.NewLine +
                "IsCurrentVirtualDesktop: " + vdm.IsWindowOnCurrentVirtualDesktop(Handle).ToString()
                );
        }
        //Timer tick to check if the window is on the current virtual desktop and change it otherwise
        //A timer does not have to be used, but something has to trigger the check
        //If the window was active before the vd change, it would trigger
        //the deactivated and lost focus events when the vd changes
        //The timer always gets triggered which makes the example hopefully less confusing
        private void VDCheckTimer_Tick(object sender, EventArgs e)
        {
            try
            {
                if (!vdm.IsWindowOnCurrentVirtualDesktop(Handle))
                {
                    using (NewWindow nw = new NewWindow())
                    {
                        nw.Show(null);
                        vdm.MoveWindowToDesktop(Handle, vdm.GetWindowDesktopId(nw.Handle));
                    }
                }
            }
            catch
            {
                //This will fail due to race conditions as currently written on occassion
            }
        }

        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            this.label1 = new System.Windows.Forms.Label();
            this.VDCheckTimer = new System.Windows.Forms.Timer(this.components);
            this.SuspendLayout();
            //
            // label1
            //
            this.label1.Dock = System.Windows.Forms.DockStyle.Fill;
            this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 13.875F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
            this.label1.Location = new System.Drawing.Point(0, 0);
            this.label1.Name = "label1";
            this.label1.Size = new System.Drawing.Size(1112, 368);
            this.label1.TabIndex = 0;
            this.label1.Text = "Example Contents";
            this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
            this.label1.Click += new System.EventHandler(this.label1_Click);
            //
            // VDCheckTimer
            //
            this.VDCheckTimer.Enabled = true;
            this.VDCheckTimer.Interval = 1000;
            this.VDCheckTimer.Tick += new System.EventHandler(this.VDCheckTimer_Tick);
            //
            // VDExampleWindow
            //
            this.AutoScaleDimensions = new System.Drawing.SizeF(12F, 25F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(1112, 368);
            this.Controls.Add(this.label1);
            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.Fixed3D;
            this.Name = "VDExampleWindow";
            this.Text = "VD Example";
            this.TopMost = true;
            this.Load += new System.EventHandler(this.VDExampleWindow_Load);
            this.ResumeLayout(false);

        }

        #endregion

        private System.Windows.Forms.Label label1;
        private System.Windows.Forms.Timer VDCheckTimer;

        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new VDExampleWindow());
        }
    }
    [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("a5cd92ff-29be-454c-8d04-d82879fb3f1b")]
    [System.Security.SuppressUnmanagedCodeSecurity]
    public interface IVirtualDesktopManager
    {
        [PreserveSig]
        int IsWindowOnCurrentVirtualDesktop(
            [In] IntPtr TopLevelWindow,
            [Out] out int OnCurrentDesktop
            );
        [PreserveSig]
        int GetWindowDesktopId(
            [In] IntPtr TopLevelWindow,
            [Out] out Guid CurrentDesktop
            );

        [PreserveSig]
        int MoveWindowToDesktop(
            [In] IntPtr TopLevelWindow,
            [MarshalAs(UnmanagedType.LPStruct)]
            [In]Guid CurrentDesktop
            );
    }

    public class NewWindow : Form
    {
    }
    [ComImport, Guid("aa509086-5ca9-4c25-8f95-589d3c07b48a")]
    public class CVirtualDesktopManager
    {

    }
    public class VirtualDesktopManager
    {
        public VirtualDesktopManager()
        {
            cmanager = new CVirtualDesktopManager();
            manager = (IVirtualDesktopManager)cmanager;
        }
        ~VirtualDesktopManager()
        {
            manager = null;
            cmanager = null;
        }
        private CVirtualDesktopManager cmanager = null;
        private IVirtualDesktopManager manager;

        public bool IsWindowOnCurrentVirtualDesktop(IntPtr TopLevelWindow)
        {
            int result;
            int hr;
            if ((hr = manager.IsWindowOnCurrentVirtualDesktop(TopLevelWindow, out result)) != 0)
            {
                Marshal.ThrowExceptionForHR(hr);
            }
            return result != 0;
        }

        public Guid GetWindowDesktopId(IntPtr TopLevelWindow)
        {
            Guid result;
            int hr;
            if ((hr = manager.GetWindowDesktopId(TopLevelWindow, out result)) != 0)
            {
                Marshal.ThrowExceptionForHR(hr);
            }
            return result;
        }

        public void MoveWindowToDesktop(IntPtr TopLevelWindow, Guid CurrentDesktop)
        {
            int hr;
            if ((hr = manager.MoveWindowToDesktop(TopLevelWindow, CurrentDesktop)) != 0)
            {
                Marshal.ThrowExceptionForHR(hr);
            }
        }
    }
}

Follow us on Twitter, www.twitter.com/WindowsSDK.

VirtualDesktopSwitch.zip

FileSystemWatcher Fencing(Part 2)

$
0
0
 

This post is a follow up to the FileSystemWatcher Follies post.  I received a lot of feedback that it would be useful to highlight what would be appropriate to guide against some of the pitfalls that I mentioned in that post.  I’ll cover several of the issues here over a couple of posts and propose things that could be done to detect that they are there before using the FileSystemWatcher class against them.  Though the code examples will all be in C#, there will be some P/Invoke involved here as not all of this functionality is exposed through .NET Framework classes at this time.

Using Change Journals

If you’ve already determined that your path is local and uses the NTFS or ReFS file system, a great alternative to the FileSystemWatcher is to use change journaling.  Change journals can be complicated, but they also give you very fine grained control over the information that you want.  However, your code must be running as an administrator or system in order to create or delete them, and they do take up some space on disk (the maximum amount that will be taken up can be specified).    Because change journals monitor an entire volume, if you’re designing an application to make optimal use of this functionality for consistent change monitoring, you may want to put the data that you’re consistently monitoring for changes on its own volume.

Other things to keep in mind when using change journals:

  1. Changes for files and directories are not full paths; parent directories are identified by IDs and those directory names can be looked up by OpenFileByID amongst other methods
  2. If BytesToRead is set to zero, it will immediately return with up to one entry; otherwise it will wait until that many bytes are filled in to the buffer or the specified timeout value.  If you want to get immediate notification
  3. It does not work on network file paths.
  4. All of the functionality works through the use of DeviceIOControl; consult the documentation for the structure type and enumeration value for additional details about how to use that value.

Basic Change Journal Wrapper

Below is sample code for a basic change journal class which monitors a volume for changes.  The changes monitored for are specifiable and the types available are included as an enumeration.  The values are hardcoded to only show file creation and delete events.  If the buffer size is set to anything less than 1024, the sample will use zero for BytesToRead to immediately return upon receiving each entry.

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Win32.SafeHandles;
using System.Runtime.InteropServices;
using System.IO;
using System.Threading;

namespace ChangeJournal
{
    public class ChangeJournalHandle : SafeHandleMinusOneIsInvalid
    {

        [DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
        private static extern IntPtr CreateFileW(
            [MarshalAs(UnmanagedType.LPWStr)]
            string FileName,
            int DesiredAccess,
            FileShare ShareMode,
            IntPtr SecurityAttributes,
            int CreationDisposition,
            int FlagsAndAttributes,
            IntPtr hTemplateFile
            );

        [DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
        private static extern int GetVolumeInformationByHandleW(
  IntPtr hFile,
  StringBuilder lpVolumeNameBuffer,
  int nVolumeNameSize,
  out int lpVolumeSerialNumber,
  out int
     lpMaximumComponentLength,
  out int lpFileSystemFlags,
  StringBuilder lpFileSystemNameBuffer,
  int nFileSystemNameSize
);



        [DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
        private static extern int DeviceIoControl(
    IntPtr hDevice,
    int dwIoControlCode,
    IntPtr lpInBuffer,
    int nInBufferSize,
    IntPtr lpOutBuffer,
    int nOutBufferSize,
    out int lpBytesReturned,
    IntPtr lpOverlapped
    );

        [DllImport("kernel32", SetLastError = true)]
        private static extern bool CloseHandle(
            IntPtr handle);


        [DllImport("kernel32", SetLastError = true)]
        private static extern IntPtr OpenFileById(
  IntPtr hFile,
  ref FILE_ID_DESCRIPTOR lpFileID,
  int                 dwDesiredAccess,
  FileShare dwShareMode,
  IntPtr lpSecurityAttributes,
  int dwFlags
);
        [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        private static extern int GetFinalPathNameByHandleW(
  IntPtr hFile,
  StringBuilder lpszFilePath,
  int cchFilePath,
  int dwFlags
);
        [StructLayout(LayoutKind.Explicit)]
        public struct FILE_ID_DESCRIPTOR
        {
            [FieldOffset(0)]
            public int Size;
            [FieldOffset(4)]
            public int Type;
            [FieldOffset(8)]
            public long FileId;
            [FieldOffset(8)]
            public Guid ObjectId;
            [FieldOffset(8)]
            public Guid ExtendedFileId; //Use for ReFS; need to use v3 structures or later instead of v2 as done in this sample
        }

        public static int CTL_CODE(int DeviceType, int Function, int Method, int Access)
        {
            return ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method);
        }

        protected override bool ReleaseHandle()
        {

            if(handle != IntPtr.Zero)
            {
                if(createdJournal == true)
                {
                    TryDeleteCurrentJournal();
                }
                StopListening(10);//this may cause a delay
                return CloseHandle(handle);
            }
            return false;
        }

        public const int FILE_DEVICE_FILE_SYSTEM = 0x00000009;
        public const int METHOD_BUFFERED = 0;
        public const int METHOD_IN_DIRECT = 1;
        public const int METHOD_OUT_DIRECT = 2;
        public const int METHOD_NEITHER = 3;
        public const int FILE_ANY_ACCESS = 0;

        public static int FSCTL_READ_USN_JOURNAL = CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 46, METHOD_NEITHER, FILE_ANY_ACCESS);
        public static int FSCTL_ENUM_USN_DATA = CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 44, METHOD_NEITHER, FILE_ANY_ACCESS);
        public static int FSCTL_CREATE_USN_JOURNAL = CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 57, METHOD_NEITHER, FILE_ANY_ACCESS);
        public static int FSCTL_READ_FILE_USN_DATA = CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 58, METHOD_NEITHER, FILE_ANY_ACCESS);
        public static int FSCTL_QUERY_USN_JOURNAL = CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 61, METHOD_BUFFERED, FILE_ANY_ACCESS);
        public static int FSCTL_DELETE_USN_JOURNAL = CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 62, METHOD_BUFFERED, FILE_ANY_ACCESS);
        public static int FSCTL_WRITE_USN_REASON = CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 180, METHOD_BUFFERED, FILE_ANY_ACCESS);
        public static int FSCTL_USN_TRACK_MODIFIED_RANGES = CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 189, METHOD_BUFFERED, FILE_ANY_ACCESS);

        [StructLayout(LayoutKind.Sequential)]
        public struct USN
        {
            public long Usn;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct MFT_ENUM_DATA_V0
        {
            public USN Low;
            public USN High;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct MFT_ENUM_DATA_V1
        {
            public long StartFileReferenceNumber;
            public USN Low;
            public USN High;
            public short MinMajorVersion;
            public short MaxMajorVersion;
        }


        [StructLayout(LayoutKind.Sequential)]
        public struct CREATE_USN_JOURNAL_DATA
        {
            public long MaximumSize;
            public long AllocationDelta;
        }


        [StructLayout(LayoutKind.Sequential)]
        public struct READ_USN_JOURNAL_DATA_V0
        {
            public USN StartUsn;
            public int ReasonMask;
            public int ReturnOnlyOnClose;
            public long Timeout;
            public long BytesToWaitFor;
            public long UsnJournalId;
        }


        [StructLayout(LayoutKind.Sequential)]
        public struct READ_USN_JOURNAL_DATA_V1
        {
            public USN StartUsn;
            public int ReasonMask;
            public int ReturnOnlyOnClose;
            public long Timeout;
            public long BytesToWaitFor;
            public long UsnJournalId;
            public short MinMajorVersion;
            public short MaxMajorVersion;
        }


        [StructLayout(LayoutKind.Sequential)]
        public struct USN_TRACK_MODIFIED_RANGES
        {
            public int Flags;
            public int Unused;
            public long ChunkSize;
            public long FileSizeThreshold;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct USN_RANGE_TRACK_OUTPUT
        {
            public USN Usn;
        }

        public const int FLAG_USN_TRACK_MODIFIED_RANGES_ENABLE = 0x00000001;

        public class UsnRecordV2WithName
        {
            public USN_RECORD_V2 Record { get; set; }
            public string Filename { get; set; }
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct USN_RECORD_V2
        {
            public int RecordLength;
            public short MajorVersion;
            public short MinorVersion;
            public long FileReferenceNumber;
            public long ParentFileReferenceNumber;
            USN Usn;
            public long TimeStamp;
            public int Reason;
            public int SourceInfo;
            public int SecurityId;
            public int FileAttributes;
            public short FileNameLength;
            public short FileNameOffset;
            //WCHAR FileName[1];

        }

        [StructLayout(LayoutKind.Sequential)]
        public struct USN_RECORD_V3
        {
            public int RecordLength;
            public short MajorVersion;
            public short MinorVersion;
            public Guid FileReferenceNumber;
            public Guid ParentFileReferenceNumber;
            USN Usn;
            public long TimeStamp;
            public int Reason;
            public int SourceInfo;
            public int SecurityId;
            public int FileAttributes;
            public short FileNameLength;
            public short FileNameOffset;
            //WCHAR FileName[1];

        }


        [StructLayout(LayoutKind.Sequential)]
        public struct USN_RECORD_COMMON_HEADER
        {
            public int RecordLength;
            public short MajorVersion;
            public short MinorVersion;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct USN_RECORD_EXTENT
        {
            public long Offset;
            public long Length;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct USN_RECORD_V4
        {
            public USN_RECORD_COMMON_HEADER Header;
            public Guid FileReferenceNumber;
            public Guid ParentFileReferenceNumber;
            public USN Usn;
            public int Reason;
            public int SourceInfo;
            public int RemainingExtents;
            public short NumberOfExtents;
            public short ExtentSize;
            public USN_RECORD_EXTENT Extents; //Extents[1]
        }


        public const int USN_PAGE_SIZE = (0x1000);
        public const int USN_REASON_DATA_OVERWRITE = (0x00000001);
        public const int USN_REASON_DATA_EXTEND = (0x00000002);
        public const int USN_REASON_DATA_TRUNCATION = (0x00000004);
        public const int USN_REASON_NAMED_DATA_OVERWRITE = (0x00000010);
        public const int USN_REASON_NAMED_DATA_EXTEND = (0x00000020);
        public const int USN_REASON_NAMED_DATA_TRUNCATION = (0x00000040);
        public const int USN_REASON_FILE_CREATE = (0x00000100);
        public const int USN_REASON_FILE_DELETE = (0x00000200);
        public const int USN_REASON_EA_CHANGE = (0x00000400);
        public const int USN_REASON_SECURITY_CHANGE = (0x00000800);
        public const int USN_REASON_RENAME_OLD_NAME = (0x00001000);
        public const int USN_REASON_RENAME_NEW_NAME = (0x00002000);
        public const int USN_REASON_INDEXABLE_CHANGE = (0x00004000);
        public const int USN_REASON_BASIC_INFO_CHANGE = (0x00008000);
        public const int USN_REASON_HARD_LINK_CHANGE = (0x00010000);
        public const int USN_REASON_COMPRESSION_CHANGE = (0x00020000);
        public const int USN_REASON_ENCRYPTION_CHANGE = (0x00040000);
        public const int USN_REASON_OBJECT_ID_CHANGE = (0x00080000);
        public const int USN_REASON_REPARSE_POINT_CHANGE = (0x00100000);
        public const int USN_REASON_STREAM_CHANGE = (0x00200000);
        public const int USN_REASON_TRANSACTED_CHANGE = (0x00400000);
        public const int USN_REASON_INTEGRITY_CHANGE = (0x00800000);
        public const uint USN_REASON_CLOSE = (0x80000000);

        [Flags]
        public enum UsnReasonType : int
        {
            USN_REASON_DATA_OVERWRITE = (0x00000001),
            USN_REASON_DATA_EXTEND = (0x00000002),
            USN_REASON_DATA_TRUNCATION = (0x00000004),
            USN_REASON_NAMED_DATA_OVERWRITE = (0x00000010),
            USN_REASON_NAMED_DATA_EXTEND = (0x00000020),
            USN_REASON_NAMED_DATA_TRUNCATION = (0x00000040),
            USN_REASON_FILE_CREATE = (0x00000100),
            USN_REASON_FILE_DELETE = (0x00000200),
            USN_REASON_EA_CHANGE = (0x00000400),
            USN_REASON_SECURITY_CHANGE = (0x00000800),
            USN_REASON_RENAME_OLD_NAME = (0x00001000),
            USN_REASON_RENAME_NEW_NAME = (0x00002000),
            USN_REASON_INDEXABLE_CHANGE = (0x00004000),
            USN_REASON_BASIC_INFO_CHANGE = (0x00008000),
            USN_REASON_HARD_LINK_CHANGE = (0x00010000),
            USN_REASON_COMPRESSION_CHANGE = (0x00020000),
            USN_REASON_ENCRYPTION_CHANGE = (0x00040000),
            USN_REASON_OBJECT_ID_CHANGE = (0x00080000),
            USN_REASON_REPARSE_POINT_CHANGE = (0x00100000),
            USN_REASON_STREAM_CHANGE = (0x00200000),
            USN_REASON_TRANSACTED_CHANGE = (0x00400000),
            USN_REASON_INTEGRITY_CHANGE = (0x00800000),
            USN_REASON_CLOSE = unchecked((int)(0x80000000))
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct USN_JOURNAL_DATA_V0
        {
            public long UsnJournalID;
            public USN FirstUsn;
            public USN NextUsn;
            public USN LowestValidUsn;
            public USN MaxUsn;
            public long MaximumSize;
            public long AllocationDelta;

        }
        [StructLayout(LayoutKind.Sequential)]
        public struct USN_JOURNAL_DATA_V1
        {
            public long UsnJournalID;
            public USN FirstUsn;
            public USN NextUsn;
            public USN LowestValidUsn;
            public USN MaxUsn;
            public long MaximumSize;
            public long AllocationDelta;
            public short MinSupportedMajorVersion;
            public short MaxSupportedMajorVersion;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct USN_JOURNAL_DATA_V2
        {
            public long UsnJournalID;
            public USN FirstUsn;
            public USN NextUsn;
            public USN LowestValidUsn;
            public USN MaxUsn;
            public long MaximumSize;
            public long AllocationDelta;
            public short MinSupportedMajorVersion;
            public short MaxSupportedMajorVersion;
            public int Flags;
            public long RangeTrackChunkSize;
            public long RangeTrackFileSizeThreshold;
        }



        [StructLayout(LayoutKind.Sequential)]
        public struct DELETE_USN_JOURNAL_DATA
        {
            public long UsnJournalID;
            public int DeleteFlags;
        }

        public int USN_DELETE_FLAG_DELETE = (0x00000001);
        public int USN_DELETE_FLAG_NOTIFY = (0x00000002);
        public int USN_DELETE_VALID_FLAGS = (0x00000003);

        public UsnReasonType EventTriggerMask
        {
            get
            {
                return (UsnReasonType)rdata.ReasonMask;
            }
            set
            {
                rdata.ReasonMask = (int)value;
            }
        }

        public long Timeout
        {
            get
            {
                return rdata.Timeout;
            }
            set
            {
                rdata.Timeout = value;
            }
        }

        public bool TriggerOnCloseOnly
        {
            get
            {
                return rdata.ReturnOnlyOnClose != 0;
            }
            set
            {
                rdata.ReturnOnlyOnClose = value ? 1 : 0;
            }
        }
        private ReaderWriterLockSlim readBufferLock = new ReaderWriterLockSlim();

        private int readBufferSize = 8192;

        //This could hang if there is a long timeout value
        public int ReadBufferSize
        {
            get
            {
                readBufferLock.EnterWriteLock();
                try
                {
                    return readBufferSize;
                }
                finally
                {
                    readBufferLock.ExitWriteLock();
                }
            }
            set
            {
                readBufferLock.EnterWriteLock();
                try
                {

                    if (value > 0)
                    {
                        if (readBuffer == IntPtr.Zero)
                        {
                            readBuffer = Marshal.AllocHGlobal(value);
                        }
                        else
                        {
                            readBuffer = Marshal.ReAllocHGlobal(readBuffer, (IntPtr)value);
                        }
                    }
                    readBufferSize = value;

                }
                finally
                {
                    readBufferLock.ExitWriteLock();
                }
            }
        }
        public event Action<ChangeJournalHandle, UsnRecordV2WithName> OnChange;
        public event Action<ChangeJournalHandle, Exception> OnError;

        private bool shouldRun = false;

        private Thread thread = null;

        public ChangeJournalHandle(string path) : base(true)
        {
            //TODO:Handle taking non-volume paths
            handle = CreateFileW(path, unchecked((int)(0x80000000 | 0x40000000)),
                FileShare.ReadWrite, IntPtr.Zero, 3, 0, IntPtr.Zero);
            if (IsInvalid)
            {
                Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
            }
        }

        public bool TryCreateJournal(long maxSize = (1024 ^ 2) * 500, long allocationDelta = 8192)
        {
            CREATE_USN_JOURNAL_DATA data = new CREATE_USN_JOURNAL_DATA();
            data.AllocationDelta = allocationDelta;
            data.MaximumSize = maxSize;
            int size = Marshal.SizeOf(data);
            IntPtr buffer = Marshal.AllocHGlobal(size);
            try
            {
                int bufSizeOut;
                int result = DeviceIoControl(handle, FSCTL_CREATE_USN_JOURNAL, buffer, size, IntPtr.Zero, 0, out bufSizeOut, IntPtr.Zero);
                if (result == 0)
                {
                    ReportLastError();
                    return false;
                }
                createdJournal = true;
                return true;
            }
            finally
            {
                Marshal.FreeHGlobal(buffer);
            }
        }
        public void CreateJournal(long maxSize = (1024 ^ 2) * 500, long allocationDelta = 8192)
        {
            CREATE_USN_JOURNAL_DATA data = new CREATE_USN_JOURNAL_DATA();
            data.AllocationDelta = allocationDelta;
            data.MaximumSize = maxSize;
            int size = Marshal.SizeOf(data);
            IntPtr buffer = Marshal.AllocHGlobal(size);
            try
            {
                int bufSizeOut;
                int result = DeviceIoControl(handle, FSCTL_CREATE_USN_JOURNAL, buffer, size, IntPtr.Zero, 0, out bufSizeOut, IntPtr.Zero);
                if (result == 0)
                {
                    Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
                }
            }
            finally
            {
                Marshal.FreeHGlobal(buffer);
            }
        }
        public bool TryDeleteCurrentJournal()
        {
            USN_JOURNAL_DATA_V0 data = new USN_JOURNAL_DATA_V0();
            int size = Marshal.SizeOf(data);
            IntPtr buffer = Marshal.AllocHGlobal(size);
            try
            {
                int outSize;
                int result = DeviceIoControl(handle, FSCTL_QUERY_USN_JOURNAL, IntPtr.Zero, 0, buffer, size, out outSize, IntPtr.Zero);
                if (result == 0)
                {
                    ReportLastError();
                    return false;
                }
                data = Marshal.PtrToStructure<USN_JOURNAL_DATA_V0>(buffer);
            }
            finally
            {
                Marshal.FreeHGlobal(buffer);
            }
            DELETE_USN_JOURNAL_DATA d = new DELETE_USN_JOURNAL_DATA();
            d.UsnJournalID = data.UsnJournalID;
            d.DeleteFlags = 3;
            size = Marshal.SizeOf(d);
            buffer = Marshal.AllocHGlobal(size);
            try
            {
                Marshal.StructureToPtr(d, buffer, false);
                if (DeviceIoControl(handle, FSCTL_DELETE_USN_JOURNAL, buffer, size, IntPtr.Zero, 0, out size, IntPtr.Zero) == 0)
                {
                    ReportLastError();
                    return false;
                }
                return true;
            }
            finally
            {
                Marshal.FreeHGlobal(buffer);
            }
        }
        public bool TryDeleteJournal(long UsnJournalID)
        {
            //Note that overloads would be needed for different versions of the structure
            DELETE_USN_JOURNAL_DATA d = new DELETE_USN_JOURNAL_DATA();
            d.UsnJournalID = UsnJournalID;
            d.DeleteFlags = 3;
            int size = Marshal.SizeOf(d);
            IntPtr buffer = Marshal.AllocHGlobal(size);
            try
            {
                Marshal.StructureToPtr(d, buffer, false);
                if (DeviceIoControl(handle, FSCTL_DELETE_USN_JOURNAL, buffer, size, IntPtr.Zero, 0, out size, IntPtr.Zero) == 0)
                {
                    ReportLastError();
                    return false;
                }
                return true;
            }
            finally
            {
                Marshal.FreeHGlobal(buffer);
            }

        }
        public void DeleteAllJournals()
        {
            try
            {
                while (true)
                {
                    USN_JOURNAL_DATA_V0 data = new USN_JOURNAL_DATA_V0();
                    int size = Marshal.SizeOf(data);
                    IntPtr buffer = Marshal.AllocHGlobal(size);
                    try
                    {
                        int outSize;
                        int result = DeviceIoControl(handle, FSCTL_QUERY_USN_JOURNAL, IntPtr.Zero, 0, buffer, size, out outSize, IntPtr.Zero);
                        if (result == 0)
                        {
                            ReportLastError();
                            break;
                        }
                        data = Marshal.PtrToStructure<USN_JOURNAL_DATA_V0>(buffer);
                    }
                    finally
                    {
                        Marshal.FreeHGlobal(buffer);
                    }
                    DELETE_USN_JOURNAL_DATA d = new DELETE_USN_JOURNAL_DATA();
                    d.UsnJournalID = data.UsnJournalID;
                    d.DeleteFlags = 3;
                    size = Marshal.SizeOf(d);
                    buffer = Marshal.AllocHGlobal(size);
                    try
                    {
                        Marshal.StructureToPtr(d, buffer, false);
                        if (DeviceIoControl(handle, FSCTL_DELETE_USN_JOURNAL, buffer, size, IntPtr.Zero, 0, out size, IntPtr.Zero) == 0)
                        {
                            ReportLastError();
                            break;
                        }
                    }
                    finally
                    {
                        Marshal.FreeHGlobal(buffer);
                    }
                }
            }
            catch (Exception ex)
            {
                ReportException(ex);
            }
        }
        public void StartListening()
        {
            //See https://msdn.microsoft.com/en-us/library/windows/desktop/aa365736(v=vs.85).aspx
            if (!shouldRun)
            {
                thread = new Thread(ListenProc);
                shouldRun = true;
                thread.Start();
            }
        }

        public void StopListening(int timeout = int.MaxValue)
        {
            if (shouldRun)
            {
                shouldRun = false;
                if (thread != null)
                {
                    if(!thread.Join(timeout))
                    {
                        thread.Abort();
                    }
                    thread = null;
                }
            }
        }

        public string GetNameForId(long id)
        {
            try
            {
                FILE_ID_DESCRIPTOR fid = new FILE_ID_DESCRIPTOR();
                fid.FileId = id;
                fid.Size = Marshal.SizeOf(fid);
                IntPtr h = OpenFileById(handle, ref fid, unchecked((int)0x80), FileShare.ReadWrite | FileShare.Delete, IntPtr.Zero, 0);
                if (h == new IntPtr(-1))
                {
                    Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
                }
                int size = 1024;
                StringBuilder sb = new StringBuilder(size);
                if (GetFinalPathNameByHandleW(h, sb, size, 0) == 0)
                {
                    int hr = Marshal.GetHRForLastWin32Error();
                    CloseHandle(h);
                    Marshal.ThrowExceptionForHR(hr);
                }
                CloseHandle(h);
                return sb.ToString();
            }
            catch(Exception ex)
            {
                ReportException(ex);
                return id.ToString("X");
            }

        }
        private READ_USN_JOURNAL_DATA_V0 rdata = new READ_USN_JOURNAL_DATA_V0() { ReasonMask = unchecked((int)0xFFFFFFFF) };
        private IntPtr readBuffer;
        private bool createdJournal = false;
        void ListenProc()
        {
            try
            {
                USN_JOURNAL_DATA_V0 data = new USN_JOURNAL_DATA_V0();
                int size = Marshal.SizeOf(data);
                IntPtr buffer = Marshal.AllocHGlobal(size);
                try
                {
                    int outSize;
                    int result = DeviceIoControl(handle, FSCTL_QUERY_USN_JOURNAL, IntPtr.Zero, 0, buffer, size, out outSize, IntPtr.Zero);
                    if (result == 0)
                    {
                        if(TryCreateJournal())
                        {
                            result = DeviceIoControl(handle, FSCTL_QUERY_USN_JOURNAL, IntPtr.Zero, 0, buffer, size, out outSize, IntPtr.Zero);
                        }
                        if(result == 0) ReportLastError();
                    }
                    if(result != 0) data = Marshal.PtrToStructure<USN_JOURNAL_DATA_V0>(buffer);
                }
                finally
                {
                    Marshal.FreeHGlobal(buffer);
                }
                rdata.UsnJournalId = data.UsnJournalID;
                rdata.StartUsn.Usn = 0;
                int rsize = Marshal.SizeOf(typeof(USN_RECORD_V2));
                size = Marshal.SizeOf(rdata);
                buffer = Marshal.AllocHGlobal(size);
                if (readBuffer == IntPtr.Zero)
                {
                    //Allocates the buffer if it's empty
                    ReadBufferSize = ReadBufferSize;
                }
                int usize = Marshal.SizeOf(typeof(USN));
                try
                {
                    List<UsnRecordV2WithName> records = new List<UsnRecordV2WithName>();
                    while (shouldRun)
                    {
                        records.Clear();
                        int outSize;
                        int result;
                        if(readBufferSize >= 1024)
                        {
                            rdata.BytesToWaitFor = readBufferSize;
                        }
                        else
                        {
                            //Returns immediately
                            rdata.BytesToWaitFor = 0;
                        }
                        Marshal.StructureToPtr(rdata, buffer, false);

                        readBufferLock.EnterReadLock();
                        try
                        {
                            result = DeviceIoControl(handle, FSCTL_READ_USN_JOURNAL, buffer, size, readBuffer, readBufferSize, out outSize, IntPtr.Zero);
                            if (result != 0 && outSize >= usize)
                            {
                                USN usn = Marshal.PtrToStructure<USN>(readBuffer);
                                rdata.StartUsn = usn;
                                int retbytes = outSize - usize;
                                IntPtr record = IntPtr.Add(readBuffer, usize);
                                while (retbytes > 0)
                                {
                                    USN_RECORD_V2 r = Marshal.PtrToStructure<USN_RECORD_V2>(record);
                                    UsnRecordV2WithName r2 = new UsnRecordV2WithName();
                                    r2.Record = r;
                                    r2.Filename = Marshal.PtrToStringUni(IntPtr.Add(record, r.FileNameOffset), (r.FileNameLength / 2));
                                    records.Add(r2);
                                    record = IntPtr.Add(record, r.RecordLength);
                                    retbytes -= r.RecordLength;
                                }
                            }
                            else
                            {
                                ReportLastError();
                            }
                        }
                        finally
                        {
                            readBufferLock.ExitReadLock();
                        }
                        foreach (var r in records)
                        {
                            ReportChange(r);
                        }
                    }
                }
                finally
                {
                    Marshal.FreeHGlobal(buffer);
                }
            }
            catch (ThreadAbortException tae)
            {

            }
        }

        void ReportChange(UsnRecordV2WithName record)
        {
            if (OnChange != null)
            {
                OnChange(this, record);
            }
        }

        void ReportLastError()
        {
            ReportException(Marshal.GetExceptionForHR(Marshal.GetHRForLastWin32Error()));
        }

        void ReportException(Exception ex)
        {
            if (OnError != null)
            {
                OnError(this, ex);
            }
        }



        private static void Cjh_OnError(ChangeJournalHandle arg1, Exception arg2)
        {
            Console.WriteLine("Error:/t{0}", arg2.ToString());
        }

        private static void Cjh_OnChange(ChangeJournalHandle arg1, UsnRecordV2WithName arg2)
        {
            //Note that it would be typically faster in the long run to build a dictionary
            //of directory names by IDs and reset it whenever the change journal resets
            //instead of looking up the directory each time
            //Also, note that if the directory is deleted before OpenFileById is called in GetNameById, it's going to fail with an out of range error
            Console.Write(arg1.GetNameForId(arg2.Record.ParentFileReferenceNumber));
            Console.Write("\\");
            Console.Write(arg2.Filename);
            Console.Write(":\t");
            Console.WriteLine(((ChangeJournalHandle.UsnReasonType)arg2.Record.Reason).ToString());
        }
        static void Main(string[] args)
        {
            string pathToVolumeToMonitor = @"\\?\C:";
            //This will filter to show only files that are deleted or created
            UsnReasonType reasonsToMonitor = UsnReasonType.USN_REASON_FILE_CREATE | UsnReasonType.USN_REASON_FILE_DELETE;
            using (ChangeJournalHandle cjh = new ChangeJournalHandle(pathToVolumeToMonitor))
            {
                cjh.OnChange += Cjh_OnChange;
                cjh.OnError += Cjh_OnError;
                cjh.EventTriggerMask = reasonsToMonitor;

                cjh.StartListening();
                Console.ReadLine();
                cjh.StopListening();


                cjh.OnChange -= Cjh_OnChange;
                cjh.OnError -= Cjh_OnError;
            }
        }
    }
}

Sample output:

\\?\C:\Windows\Temp\MSIc9528.LOG:       USN_REASON_FILE_CREATE

\\?\C:\Windows\Temp\MSIc9528.LOG:       USN_REASON_FILE_CREATE, USN_REASON_CLOSE

\\?\C:\Windows\Temp\MSIc9529.LOG:       USN_REASON_FILE_CREATE

\\?\C:\Windows\Temp\MSIc9529.LOG:       USN_REASON_FILE_CREATE, USN_REASON_CLOSE

\\?\C:\Windows\Temp\MSIc952a.LOG:       USN_REASON_FILE_CREATE

\\?\C:\Windows\Temp\MSIc952a.LOG:       USN_REASON_FILE_CREATE, USN_REASON_CLOSE

\\?\C:\Windows\Temp\MSIc952b.LOG:       USN_REASON_FILE_CREATE

\\?\C:\Windows\Temp\MSIc952b.LOG:       USN_REASON_FILE_CREATE, USN_REASON_CLOSE

 

 

 

Follow us on Twitter, www.twitter.com/WindowsSDK.

Windows Hotfixes for October 2015

$
0
0

Jeff here from the Windows SDK team. Here is the list of October 2015 Hotfixes

[Drum roll, please…]

KB3030736   “550 The process cannot access the file” error when you try to download a file in Windows

KB3044546   An updated reservation may disappear on a DHCP failover cluster in Windows Server 2012 or Windows Server 2012 R2

KB3049591   Transparent areas are printed as black when you use a v4 XPS printer driver in Windows

KB3053667   Users can’t connect to virtual machines that are running Windows 8.1 or Windows Server 2012 R2 by remote desktop

KB3077354   Computer freezes when WFP leaks nonpaged pool memory in Windows Server 2012 R2 or Windows Server 2012

KB3084093   Child nodes under protected OU are deleted in Windows Server 2012 R2

KB3084426   System becomes unresponsive when file system minifilter drivers are installed in Windows 8 or Windows Server 2012

KB3084787   Event ID 4102 when DFS Replication cloning fails on a Windows Server 2012 R2-based cluster

KB3084953   OOBE crashes when you enter SIM card PIN in Windows 8.1

KB3084956   You can’t log on to a domain-joined computer in Windows 8 or Windows Server 2012

KB3084983   SetOptions or GetOptions method doesn’t work for PRINTER_PROPERTY features in Windows

KB3086644   System freezes after you start a backup task for virtual machines in Windows Server 2012 R2

KB3090322   Space doesn’t regenerate upon reallocation in Windows Server 2012 R2

KB3090973   Reenlist can’t be called when SQL Server receives transaction outcome from MSDTC in Windows Server 2012 R2

KB3091057   Cluster validation fails in the “Validate Simultaneous Failover” test in a Windows Server 2012 R2-based failover cluster

KB3091061   Update to add CSVFS tracing for performance issues during backup operations in Windows Server 2012 R2

KB3091342   Computer crashes after you install update 3000850 in Windows 8.1

KB3091402   Site-to-site VPN goes down when you set a VNet-to-VNet connection in Azure in Windows 8.1 or Windows Server 2012 R2

KB3091403   High CPU usage for 12 seconds on a multiple-network-adapters computer in Windows Server 2012 R2 or Windows Server 2012

KB3092002   Set-Acl cmdlet fails although delegated admins have “Change Permissions” enabled in Windows Server 2012 R2

KB3092003   Page loads repeatedly and authentication fails when users use MFA in Windows Server 2012 R2 AD FS

KB3092005   Group Policy settings are set back to factory settings in GPMC in Windows Server 2012 R2

KB3092006   Subfolders disappear from FSRM console after you rename the root folder in Windows Server 2012 R2 or Windows Server 2012

KB3092695   Licensing report file is corrupted in Windows Server 2012 R2 RDS environments for large report files

KB3093550   All ScriptProperty members are invoked when you run the Add-Member PowerShell command in Windows 8.1

KB3093571   Update to replicate multiple VM groups and VMs that use shared VHDs in Windows Server 2012 R2 or Windows Server 2012

KB3093803   Error 0x800704C9 occurs when you try to copy file to NFS share in Windows 8 or Windows Server 2012

KB3093899   VMs that run on CSVs fail if DCM can’t query volumes in Windows Server 2012 R2

KB3093900   0x50 Stop error and users can’t access documents on shared folders or home folders in Windows Server 2012 R2

KB3094197   Files aren’t fully optimized and a deduplication cache lock contention issue occurs in Windows Server 2012 R2

KB3094199   Application module can’t receive correct process status after security update 3045999 is installed in Windows

KB3094202   Directory listing fails when sharing violations occur on Windows Server 2012 R2 or Windows Server 2012-based NFS server

KB3094446   Authentication through proxy fails in Windows Server 2012 or Windows Server 2008 R2 SP1

KB3095308   VMs may not get additional memory although they’re set to use Dynamic Memory in Windows Server 2012 R2

KB3095319   You receive an error message when you use GPMC to manage audit policies in Windows 8.1 or Windows Server 2012 R2

KB3095663   VSS_E_PROVIDER_VETO error occurs when you restore a LUN from backup in Windows Server 2012 R2

KB3095711   Update to support LTO-7 tape drives in Windows Server 2012 R2 and Windows Server 2012

KB3095737   Azure Backup takes a long time to back up data with a guest OS that’s running Windows Server 2012

Happy patching…

/Jeff

Follow us on Twitter, www.twitter.com/WindowsSDK.

 


Hotfixes for November 2015

$
0
0

Jeff here from the SDK team. Here are the hotfixes for November 2015.

KB3040017   XPS driver is slower than GDI driver to print files in Windows

KB3063109   Virtual machine crashes and WAL consistency is not maintained for Guest clustered VMs in Windows Server 2012 R2

KB3078414   NFS service freezes on a Windows Server 2012 cluster and a client computer can’t access NFS share

KB3080141   Cluster service freezes on a Windows Server 2012 R2 or Windows Server 2012-based failover cluster

KB3086918   Original file is lost with new file not being saved in WebDAV folder in Windows 8.1

KB3091411   User connection fails when many connections are made to Windows Server 2012 R2-based RD Connection Broker

KB3092604   Network is corrupted between Guest OS and external network for VMs hosted on Windows 8.1 or Windows Server 2012 R2

KB3092688   UPD profiles corrupted when a network connectivity issue occurs in Windows Server 2012 R2

KB3095113   Update to enable WSUS support for Windows 10 feature upgrades

KB3095682   File Explorer shows thumbnail contents even though files are marked with offline flag in Windows

KB3098841   Application crashes with access violation error in Windows 7 or Windows Server 2008 R2

KB3100460   Video stops playing unexpectedly when another video pauses in the same application in Windows 8 or Windows Server 2012

KB3100474   Can’t connect to wireless network when you resume the computer from hibernate mode in Windows

KB3100477   A large file upload or a large repository clone fails on VSO in Windows Server 2012 R2

KB3100527   System becomes unresponsive and crashes on Windows Server 2012 R2-based file servers

KB3100530   Windows backup fails with no sufficient free space on target volume in Windows Server 2012

KB3101217   Client requests take a long time to execute or COM+ application freezes in Windows 7 SP1 or Windows Server 2008 R2 SP1

KB3101694   “0x000000D1″ Stop error in Pacer.sys when there’s heavy QoS traffic in Windows Server 2012 R2

KB3101705   Schema load failures or SPF failures in Windows Server 2012 R2 in Turkey

KB3101718   Application freezes when you switch the system from DC mode to AC mode in Windows 8.1 or Windows Server 2012 R2

KB3102236   Group membership removal operation fails when this operation is for a deleted user account in Windows Server 2008 R2

KB3102242   Computer crashes or restarts unexpectedly when it’s resumed from sleep mode in Windows

KB3102354   Hyper-V generation 2 virtual machines can’t start with some pass-through disks in Windows Server 2012 R2

KB3102770   The chkdsk command together with the spotfix option doesn’t fix extended volumes corruption in Windows Server 2012 R2

KB3103000   RemoteApp windows disappear and screen flickers when you switch between windows in Windows 8.1 or Windows Server 2012 R2

KB3103616   WMI query doesn’t work in Windows Server 2012

KB3105881   Can’t access applications when device authentication is enabled in Windows Server 2012 R2-based AD FS server

Happy patching.

/Jeff

Follow us on Twitter, www.twitter.com/WindowsSDK.

Using SHA256 with the SignedXml Class

$
0
0

With the industry moving away from SHA1 including Microsoft (see http://social.technet.microsoft.com/wiki/contents/articles/32288.windows-enforcement-of-authenticode-code-signing-and-timestamping.aspx), many developers should start using SHA2 in their code.  There are resources on the internet that describe how to use SHA256 with SignedXml. This blog is meant to summarize it in one place.

First of all, we need to register a SignatureDescription class that defines the DigestAlgorithm as SHA256.  The .NET Cryptography namespace implements a class called RSAPKCS1SHA1SignatureDescription that supports SHA1.  So we need a similar class called RSAPKCS1SHA256SignatureDescription that supports SHA256.

If your code is based on .NET 4.5 or higher, there is an RSAPKCS1SHA256SignatureDescription class you can register.  You have to reference the System.Deployment assembly in your project.  The full namespace is System.Deployment.Internal.CodeSigning.RSAPKCS1SHA256SignatureDescription.  You must call CryptoConfig.AddAlgorithm to register the class.

Here’s the MSDN SignedXml sample modified to use SHA256:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography.Xml;
using System.Xml;
using System.Deployment.Internal.CodeSigning;
               
namespace SignVerify
{
    public class SignVerifyEnvelope
    {
        public static void Main(String[] args)
        {
            try
            {
                CryptoConfig.AddAlgorithm(typeof(RSAPKCS1SHA256SignatureDescription), “http://www.w3.org/2001/04/xmldsig-more#rsa-sha256″);
               
                // Generate a signing key.
                RSACryptoServiceProvider Key = new RSACryptoServiceProvider();
               
                // Create an XML file to sign.
                CreateSomeXml(“Example.xml”);
                Console.WriteLine(“New XML file created.”);
               
                // Sign the XML that was just created and save it in a
                // new file.
                SignXmlFile(“Example.xml”, “signedExample.xml”, Key);
                Console.WriteLine(“XML file signed.”);
               
                // Verify the signature of the signed XML.
                Console.WriteLine(“Verifying signature…”);
                bool result = VerifyXmlFile(“SignedExample.xml”, Key);
               
                // Display the results of the signature verification to
                // the console.
                if (result)
                {
                    Console.WriteLine(“The XML signature is valid.”);
                }
                else
                {
                    Console.WriteLine(“The XML signature is not valid.”);
                }
            }
            catch (CryptographicException e)
            {
                Console.WriteLine(e.Message);
            }
        }
        // Sign an XML file and save the signature in a new file. This method does not 
        // save the public key within the XML file.  This file cannot be verified unless 
        // the verifying code has the key with which it was signed.
        public static void SignXmlFile(string FileName, string SignedFileName, RSA Key)
        {
            // Create a new XML document.
            XmlDocument doc = new XmlDocument();
               
            // Load the passed XML file using its name.
            doc.Load(new XmlTextReader(FileName));
               
            // Create a SignedXml object.
            SignedXml signedXml = new SignedXml(doc);
               
            // Add the key to the SignedXml document.
            signedXml.SigningKey = Key;
            signedXml.SignedInfo.SignatureMethod = “http://www.w3.org/2001/04/xmldsig-more#rsa-sha256″;
               
            // Create a reference to be signed.
            Reference reference = new Reference();
            reference.Uri = “”;
               
            // Add an enveloped transformation to the reference.           
            reference.AddTransform(new XmlDsigEnvelopedSignatureTransform());
            reference.AddTransform(new XmlDsigExcC14NTransform());
            reference.DigestMethod = “http://www.w3.org/2001/04/xmlenc#sha256″;
               
            // Add the reference to the SignedXml object.
            signedXml.AddReference(reference);
               
            // Compute the signature.
            signedXml.ComputeSignature();
               
            // Get the XML representation of the signature and save
            // it to an XmlElement object.
            XmlElement xmlDigitalSignature = signedXml.GetXml();
               
            // Append the element to the XML document.
            doc.DocumentElement.AppendChild(doc.ImportNode(xmlDigitalSignature, true));
            if (doc.FirstChild is XmlDeclaration)
            {
                doc.RemoveChild(doc.FirstChild);
            }
               
            // Save the signed XML document to a file specified
            // using the passed string.
            XmlTextWriter xmltw = new XmlTextWriter(SignedFileName, new UTF8Encoding(false));
            doc.WriteTo(xmltw);
            xmltw.Close();
        }
               
        // Verify the signature of an XML file against an asymetric
        // algorithm and return the result.
        public static Boolean VerifyXmlFile(String Name, RSA Key)
        {
            // Create a new XML document.
            XmlDocument xmlDocument = new XmlDocument();
               
            // Load the passed XML file into the document.
            xmlDocument.Load(Name);
               
            // Create a new SignedXml object and pass it
            // the XML document class.
            SignedXml signedXml = new SignedXml(xmlDocument);
               
            // Find the “Signature” node and create a new
            // XmlNodeList object.
            XmlNodeList nodeList = xmlDocument.GetElementsByTagName(“Signature”);
               
            // Load the signature node.
            signedXml.LoadXml((XmlElement)nodeList[0]);
               
            // Check the signature and return the result.
            return signedXml.CheckSignature(Key);
        }
        // Create example data to sign.
        public static void CreateSomeXml(string FileName)
        {
            // Create a new XmlDocument object.
            XmlDocument document = new XmlDocument();
               
            // Create a new XmlNode object.
            XmlNode node = document.CreateNode(XmlNodeType.Element, “”, “MyElement”, “samples”);
               
            // Add some text to the node.
            node.InnerText = “Example text to be signed.”;
               
            // Append the node to the document.
            document.AppendChild(node);
               
            // Save the XML document to the file name specified.
            XmlTextWriter xmltw = new XmlTextWriter(FileName, new UTF8Encoding(false));
            document.WriteTo(xmltw);
            xmltw.Close();
        }
    }
}
               
If your code is based on .NET 4.0 or you prefer not to depend on System.Deployment you can implement your own RSAPKCS1SHA256SignatureDescription class.
Shawn Neal at GitHub provides a good implementation – https://gist.github.com/sneal/f35de432115b840c4c1f#file-rsapkcs1sha256signaturedescription.  
One thing though, Microsoft recommends that you avoid using any managed classes.  You should change SHA256Managed to SHA256CryptoServiceProvider.
.NET versions below 4.0 won’t work because the CryptoConfig class did not provide the AddAlgorithm method to add additional algorithms to the internal algorithm table.
                             

SHA-1 Code Signing Deprecation in Windows beginning January 1, 2016

$
0
0

This post is to help the product team spread the word on Windows (version 7 and higher) and Windows Server will no longer trust any code that is signed with a SHA-1 code signing certificate and that contains a timestamp value greater than January 1,2016, effective January 1, 2016.

For more information or to get the latest information on this topic, please check out the following WIKI on Microsoft Technet, http://aka.ms/sha1

Hotfixes for December 2015

$
0
0

Jeff here, from the SDK team with the Holiday Hotfixes. Happy patching.

KB2920591   High CPU usage and performance issues occur when access-based enumeration is enabled in Windows 7 Service Pack 1 or Windows Server 2008 R2 Service Pack 1

KB3084463   WSUSutil.exe csaimport fails upon import in Windows Server 2012 R2 or Windows Server 2012

KB3095319   You receive an error message when you use GPMC to manage audit policies in Windows 8.1 or Windows Server 2012 R2

KB3102997   Data is corrupted after iSCSI sessions or paths recover in Windows Server 2012 R2 or Windows Server 2012

KB3102998   Application can’t connect to iSCSI servers in Windows Server 2012 R2 or Windows Server 2012

KB3106296   Can’t connect to a wireless network when you resume the computer from hibernation

KB3107128   Search result is incomplete if search criteria contain digits in Windows

KB3108319   VSS backup of the PI Data server fails and the computer crashes in Windows 8.1 or Windows Server 2012 R2

KB3109093   Applications can’t communicate over TCP loopback path in Windows 8.1 or Windows Server 2012 R2

KB3109099   Update adds support for the slow timer in LACP in Windows Server 2012 R2

KB3109156   Applications may freeze when ADSI APIs waits infinitely for server to respond in Windows Server 2012 R2

KB3109600   Users can’t log on to Outlook Web App client from a browser in Windows

KB3109973   Backup fails with a “File Not Found” error on a Windows Server 2012 R2 cluster

KB3114133   Windows Server Backup fails when you back up multiple volumes in Windows Server 2012 R2

Happy Holidays,

/Jeff

Follow us on Twitter, www.twitter.com/WindowsSDK.

Why CryptCATAdminCalcHashFromFileHandle fails with a seemingly unexpected error code

$
0
0

CryptCATAdminCalcHashFromFileHandle can fail when evaluating a file path to an executable while setting the last error code to 0x800700c1.  It’s an HRESULT instead of just an error code, but the relevant portion of the error code is 0xc1 (193L).  That is the error code for ERROR_BAD_EXE_FORMAT.  In some cases, this will happen even though the executable can run without an error.  So why would this function return ERROR_BAD_EXE_FORMAT when directly executing the file works without issue?

There are actually several reasons why this error can be returned, and only some of them would actually prevent an executable from being able to run on an unrestricted system.  All of them come from the portable executable (PE) header of the file.  The types used below can be found in the Windows SDK, primarily in winnt.h.  Here are most of the reasons:

  • PIMAGE_DOS_HEADER->e_magic is an invalid value
  • PIMAGE_DOS_HEADER->e_lfanew is an invalid value
  • PIMAGE_NT_HEADERS->Signature is an invalid value
  • PIMAGE_NT_HEADERS->FileHeader.SizeOfOptionalHeader is an invalid value
  • PIMAGE_NT_HEADERS->FileHeader.Machine is an invalid value
  • PIMAGE_NT_HEADERS->OptionalHeader.Magic is an invalid value
  • PIMAGE_NT_HEADERS->OptionalHeader.FileAlignment is an invalid value
  • Any of the populated members of PIMAGE_NT_HEADERS->OptionalHeader.DataDirectory have invalid values
  • The certificate directory (IMAGE_DIRECTORY_ENTRY_SECURITY) has an offset that puts its data in an invalid location; see https://msdn.microsoft.com/en-us/windows/hardware/gg463180 for more details on what the standards for that are.

If you encounter this error on an executable file, these can be identified manually by looking at the output of a couple of tools.  If there’s a problem with the IMAGE_DIRECTORY_ENTRY_SECURITY section, then running SignTool.exe verify /v filename will output “SignTool Error: File not valid: filename”.  The rest of them can be identified by looking through the output of dumpbin.exe.  Dumpbin is available through Visual Studio and SignTool is available through the Windows SDK.

Follow us on Twitter, www.twitter.com/WindowsSDK.

Viewing all 27 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>