Cygwin SSHD PubKey Authentication

This is an older topic for me – SSH Server (sshd) on Windows 10. There’s a built-in Windows feature for this (Windows 1809 and newer) but in my case I need to run lots of bash commands that the Windows SSH server doesn’t support. (For that matter – the OpenSSHD project didn’t meet my needs for the same reason – it uses a Windows Command shell and it’s not convenient to spawn off a Cygwin bash shell from it.) So today’s article is on how I fixed this problem.

The Cygwin SSH Server

Cygwin has a perfectly good SSH Server – you install it with: ssh-host-config and generally everything sets up fine… until I tried to use public key authentication (pubkeyauthentication in /etc/sshd_config). That actually turned out to be…challenging even in late 2020.

What was the problem?

  • I initially ran the standard Cygwin SSHD setup with absolutely no deviation from the defaults (in fact, I used ssh-host-config -y to accept the defaults).
  • I was able to login remotely as a regular user using password authentication.
  • When I tried to use public key authentication I received the dreaded
    "seteuid :operation not permitted"
    (see this article for an example).

So the failing command for me was:

ssh -i ~/.ssh/id_rsa abruce@[windows-host]
In that command the -i option specifies the private key to use. In my /etc/sshd_config file I had disabled PasswordAuthentication and restarted the Cygwin SSH server – this means that there was no fallback if the public key authentication failed. I had also copied my corresponding public key (~/.ssh/ to the Windows box and placed it in the ~/.ssh/authorized_keys file (and set permission to 0600 as required by the SSH server).

Fixing this problem was a bit of a rabbit hole as Windows helpfully makes things pretty difficult in terms of user context and permissions and Cygwin had also helpfully fudged up some of the NT permissions on my home directory.

My Solution

So here is my Recipe Which Worked:
  • Setup a separate user for Cygwin SSHD service. Technically this probably isn’t necessary because by default Cygwin uses the Local System account to run the service; this account already has loads of permissions granted to it. However, IMO creating a separate user specifically for the Cygwin SSHD service made it easier for me to identify exactly which permissions I needed to set.
    1. Create the Windows user. I created a Windows user named cygsshd and made it an Administrator.
    2. Set User Rights. I then also added specific user rights (permissions) via the secpol.msc Local Security Policy snapin tool. (You can run that command from an Elevated Command Prompt.) Inside the tool, expand the Local Policies / User Rights Assignment and set the following permissions for the new account:
      • Act as part of the operating system
      • Create a token object
      • Log on as a service
      • Replace a process level token
    3. Remove Unnecessary Rights. My new user should not be permitted to login from the network or via Remote Desktop (Terminal Services). So I explicitly deny these rights:
      • Deny access to this computer from the network
      • Deny log on through Remote Desktop Services
    4. Reboot! OK – this should not be truly necessary but I kept running into strange permission issues and rebooting did magically fix my problems. I’d do it again just to save aggravation.
  • Prepare Cygwin for your remote SSH users.

    To keep things simple, let’s treat Cygwin like we would a Linux box – we need to have entries in /etc/passwd for our users. (See my Caveats section below.)

    In my case I just have one local user that I want to login via SSH so I used the following from an Elevated Cygwin shell:

    mkpasswd -l -u abruce >> /etc/passwd

    I ran the same command for my Cygwin SSHD service user (cygsshd) but it probably isn’t necessary. Here’s the command for that user:

    mkpasswd -l -u cygsshd >> /etc/passwd

  • Rerun Cygwin SSH Server Setup. For this I simply specified to use the cygsshd user I created above:
    ssh-host-config -y --user cygsshd --pwd [the_password]
    In the above replace [the_password] with the Windows password you assigned to the cygsshd user. This command runs with all of the default values other than then --user option.
  • Start the Cygwin SSH Server. The Cygwin SSH Server is installed as a Windows Service by the ssh-host-config command. Start that service and verify it runs correctly.

Troubleshoot the process.

Running the above recipe should have been all that was necessary. It was not. While my actions “fixed” the seteuid problem I initially had – I still could not login as my local user. The errors were that my Windows “home” directory (C:\Users\abruce in my case) had “bad ownership or modes”. There is a great article on this but the problem was that the first listed command (chmod go-w ~/) failed with a Permission Denied error.

First Step: Run the SSH Server in Debug Mode. The first step in debugging any SSH Server failure is to run the SSH Server in debug mode. Here’s how:

  1. Stop the Cygwin SSH Service if it is running.
  2. Open a Cygwin shell as the cygsshd Windows user.
  3. Run the SSH Server manually:
    /usr/sbin/sshd -ddd
From that point you can connect remotely and see all of the debug / detail messages about establishing the SSH connection. This is how I learned that I (first!) had the seteuid problem and (second!) that my C:\Users\abruce homd directory permissions had “bad ownership or modes.”

So my second set of problems turned out to be Windows Permissions on my own home directory! For some reason the owner of C:\Users\abruce was actually the Windows SYSTEM account. I fixed by using Windows Explorer to get the Security properties on that account:

  • Take Ownership. First – Windows reported that security permissions were “mis-ordered” – but because my user account wasn’t the owner and didn’t have control of my home directory I couldn’t fix it. So I had to use the “Change Owner” function from the Windows Explorer advanced security properties. There were a lot of subfolders (like Application Data) that failed for me to take ownership but this turned out to be just an annoyance and not a blocker.
  • Grant Full Control. Once I had ownership of my home directory I promptly let Windows “fix” the “mis-ordered” security permissions and then I took Full Control of my home directory and all lower-level folders. Again – I got a number of errors during this process as when I took ownership these popup errors turned out not to be blockers. (Thanks, Microsoft.)
  • Verify Cygwin Permission on the home directory. After doing both the above steps – I *still* had the same “bad ownership or modes” message. Fudge! The final step turned out to be that my actual Cygwin Permissions on my own home folder were incorrect (I assure you I never set those permissions on my own – go figure). The answer? Run the following from an Elevated Cygwin shell (so you have admin privileges):
    • Change to the directory. In my case:
      cd /cygdrive/c/Users/abruce
    • Set the directory permissions using the Cygwin command:
      chmod 0750 .


After performing all of the above steps I could finally login to my Cygwin SSH server - running as a Windows Service - using Public Key authentication.


Note in this article I'm just working with local users - if you have a domain setup then things will be different. For example, you wouldn't necessarily have an entry for your users in /etc/passwd as domain logins are handled differently. YMMV.

Team-oriented systems mentor with deep knowledge of numerous software methodologies, technologies, languages, and operating systems. Excited about turning emerging technology into working production-ready systems. Focused on moving software teams to a higher level of world-class application development. Specialties:Software analysis and development...Product management through the entire lifecycle...Discrete product integration specialist!

Leave a Reply

Your email address will not be published.


Human Verification: In order to verify that you are a human and not a spam bot, please enter the answer into the following box below based on the instructions contained in the graphic.