Skip to content

sudo command does not work in remote session to Linux machine #1527

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
PaulHigin opened this issue Jul 26, 2016 · 35 comments
Closed

sudo command does not work in remote session to Linux machine #1527

PaulHigin opened this issue Jul 26, 2016 · 35 comments
Labels
Resolution-No Activity Issue has had no activity for 6 months or more Size-MultipleWeeks WG-Remoting PSRP issues with any transport layer

Comments

@PaulHigin
Copy link
Contributor

Steps to reproduce

  1. Build and setup SSH based remoting (see docs) on a Linux machine
  2. Start an interactive remote session to the same machine
    Enter-PSSession -HostName -UserName
    [] C:> sudo ls /proc/powershell

Expected behavior

sudo command to run in remote interactive session.

Actual behavior

sudo : sudo: no tty present and no askpass program specified
    + CategoryInfo          : NotSpecified: (sudo: no tty pr...ogram specified:String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError

Environment data

Name Value


PSVersion 5.1.10032.0
PSEdition PowerShellCore
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
BuildVersion 3.0.0.0
GitCommitId v0.6.0-392-ga5b5dc576b8006c0d0a83a5c538f382d9fa65dc6
CLRVersion
WSManStackVersion 3.0
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1

@PaulHigin PaulHigin self-assigned this Jul 26, 2016
@SteveL-MSFT SteveL-MSFT modified the milestone: 6.0.0-Alpha.11 Aug 4, 2016
@SteveL-MSFT SteveL-MSFT added the WG-Remoting PSRP issues with any transport layer label Sep 16, 2016
@SteveL-MSFT SteveL-MSFT modified the milestones: 6.0.0-beta, 6.0.0 Jan 23, 2017
@PaulHigin PaulHigin removed their assignment Feb 8, 2017
@SteveL-MSFT SteveL-MSFT modified the milestones: 6.0.0-beta2, 6.0.0-beta1 Mar 15, 2017
@SteveL-MSFT SteveL-MSFT modified the milestones: 6.0.0-beta, 6.0.0 May 15, 2017
@joeyaiello joeyaiello modified the milestones: 6.0.0-HighPriority, 6.0.0 May 23, 2017
@SteveL-MSFT SteveL-MSFT modified the milestones: 6.1.0, 6.0.0-HighPriority Sep 10, 2017
@SteveL-MSFT SteveL-MSFT modified the milestones: 6.1.0-Consider, Future Jun 20, 2018
@SteveL-MSFT SteveL-MSFT modified the milestones: Future, 6.3-Consider Feb 19, 2019
@SteveL-MSFT SteveL-MSFT removed this from the 7.0-Consider milestone Dec 10, 2019
@PaulHigin
Copy link
Contributor Author

Thanks for looking into this. Yes, PowerShell remoting does now support passing SecureString objects over all platforms, but unfortunately was only added to 7.1+ versions.

I am not worried about prompting for sudo password over a remote session, that can be handled with remote host calls, and probably an update to the protocol (PSRP). My main concern was how to interface with sudo, and it looks like @awakecoding 'AskPass' is the mechanism to use. It would be nice if there was some sort of API hook, but the above PoC may be workable.

@TylerLeonhardt
Copy link
Member

make it so

Anyone interested in prototyping this?

@jborean93
Copy link
Collaborator

jborean93 commented Nov 26, 2020

Slight bump, since pwsh 7.1 is out I've tweaked the script for SUDO_ASKPASS to use a secure string

#!/usr/bin/env pwsh

# Parent is sudo, grandparent is the pwsh process
$parentPid = (Get-Process -Id $pid).Parent.Parent.Id

# First arg is the prompt from sudo itself
$sudoPrompt = $args[0]

$ci = [Management.Automation.Runspaces.NamedPipeConnectionInfo]::new($parentPid)
$rs = $ps = $null
try {

    $rs = [runspacefactory]::CreateRunspace($ci)
    $rs.Open()
    $ps = [powershell]::Create()
    $ps.Runspace = $rs
    $null = $ps.AddScript({
        $rs = Get-Runspace 1
        $remoteHost = $rs.GetType().GetProperty('Host', 60).GetValue($rs)
        $remoteHost.UI.Write($args[0])
        $remoteHost.UI.ReadLineAsSecureString()
    }).AddArgument($sudoPrompt)

    $output = $ps.Invoke()

    if ($output) {
        $pass = [PSCredential]::new('noop', $output[0]).GetNetworkCredential().Password
        return $pass
    }
} finally {
    if ($null -ne $ps) {
        $ps.Dispose()
    }

    if ($null -ne $rs) {
        $rs.Dispose()
    }
}

Connecting over SSH PSRemoting this is what happens

[192.168.0.66]: PS /home/jborean> $env:SUDO_ASKPASS = '/tmp/askpass.ps1'
[192.168.0.66]: PS /home/jborean> sudo -A whoami
[sudo] password for jborean: ********
root

We can see that the actual sudo prompt appears and the password that I typed in is hidden behind * as the remote Host UI call is ReadLineAsSecureString. This solves the more serious problems I had with the implementation but there are a few other things that should be solved

  1. The current script logic just get's the pid of the grandparent process.

This is fine if sudo was called from pwsh directly, but say you are running a script which calls sudo then this won't work. We would need to work up the process tree until it comes to the PSRemoting pwsh process. In reality a less brittle way would be to smuggle in that information into the askpass.ps1 script, maybe through an env var, so we aren't 2nd guessing ourselves

  1. You need to call sudo with -A

Without -A then sudo won't call the askpass script defined in the env var. Existing scripts would need to be modified We could find a way to make a custom sudo script that just recalls sudo -A higher in the PATH priority but now sudo called with an absolute path won't work.

Maybe someone knows a sudo configuration that sets -A as the default

  1. The Runspace ID is hardcoded to 1

This works fine for a normal Enter-PSSession but we probably want to smuggle in the actual Runspace GUID so we use the correct attached PSHost. This would probably involve some more env vars that need to be smuggled in like the pwsh PID.

  1. We have to use reflection to get the Host

Ideally it would be great if we could get the PSHost without relying on any private/protected properties but I'm unsure if that's going to be possible.

There are some UX concerns I have as well, namely

  1. This script needs to be on the remote host somewhere and set as executable
  2. The user needs to set the SUDO_ASKPASS env var
  3. Probably some more friendly error messages for bad scenarios in the askpass.ps1. Luckily exceptions and errors raised in the script appear in the output normally
  4. Maybe sudo -A configuration needs to tweaking by the user

In my mind this should all be transparent to the end user but even that is fraught with danger.

@jborean93
Copy link
Collaborator

Oh and because feedback on failures is also important, here is what happens when you put in the wrong password

[192.168.0.66]: PS /home/jborean> sudo -A whoami
[sudo] password for jborean: ****
Sorry, try again.
[sudo] password for jborean:

Also when you press CTRL+C

[192.168.0.66]: PS /home/jborean> sudo -A whoami
[sudo] password for jborean: ****
Sorry, try again.
[sudo] password for jborean: no password was provided
sudo: 1 incorrect password attempt

@TylerLeonhardt
Copy link
Member

@jborean93 this is awesome. This completely proves that this solution is the right way forward.

My thinking on your UX concerns... Most of the concerns can be solved with a module + overriding sudo with a sudo function...although it feels weird.

Theoretically a user could install a module (called pseudo? 😅). that module has a psm1 that contains a single exported function called sudo.

This script needs to be on the remote host somewhere and set as executable

Module installation is simple, and in the psm1 the call to chmod to make the file executable could be done (chmod might require sudo in some cases...)

The user needs to set the SUDO_ASKPASS env var

Again in the psm1 we can set this env var.

In reality a less brittle way would be to smuggle in that information into the askpass.ps1 script, maybe through an env var, so we aren't 2nd guessing ourselves

We could do this in the sudo function. Set a POWERSHELL_PID_FOR_SUDO env var before calling the sudo exe.

In reality a less brittle way would be to smuggle in that information into the askpass.ps1 script, maybe through an env var, so we aren't 2nd guessing ourselves

Same deal. A POWERSHELL_RUNSPACE_FOR_SUDO env var. These should get cleaned up after invocation... Though, tbh... This is not a very important work item. Runspace 1 should exist in most of not all scenarios.

We have to use reflection to get the Host

A PowerShell API feature request. This should be a separate issue... But I totally agree.

@jborean93 interested in throwing a module up on the Gallery for this?

@jborean93
Copy link
Collaborator

jborean93 commented Nov 29, 2020

Most of the concerns can be solved with a module + overriding sudo with a sudo function...although it feels weird.

While it does still help in these scenarios I think this request goes beyond just calling sudo in PowerShell itself. If you want just a generic function that invokes the command with sudo this will definitely work but there are other ways to pass in a password to sudo that doesn't involve creating a file, e.g. 'password' | sudo -S @arguments.

What I feel like this example solves is a way to automatically get the prompt from sudo regardless of how it's called back to the PSHost. That allows me to run a bash script that may contains sudo my_command like ./my_script.sh in PowerShell and it would work like it does through other shells/ssh. For this to occur today you would have to have a user call a script like the below to set up the environment but it would be nice if this wasn't needed (although I don't see how based on how PSRP works today).

Function Enable-SudoPrompt {
    [CmdletBinding()]
    param()

    $tempPath = [IO.Path]::GetTempFileName()
    
    # Probably a better way but just for testing
    $cleanupAction = [ScriptBlock]::Create("Remove-Item -Path '$tempPath'")
    $null = Register-EngineEvent -SourceIdentifier PowerShell.Exiting -Action $cleanupAction
    
    $askPassScript = '@
#!/usr/bin/env pwsh

# Parent is sudo, grandparent is the pwsh process
$parentPid = {0}

# First arg is the prompt from sudo itself
$sudoPrompt = $args[0]

$ci = [Management.Automation.Runspaces.NamedPipeConnectionInfo]::new($parentPid)
$rs = $ps = $null
try {

    $rs = [runspacefactory]::CreateRunspace($ci)
    $rs.Open()
    $ps = [powershell]::Create()
    $ps.Runspace = $rs
    $null = $ps.AddScript({
        $rs = Get-Runspace -InstanceId '{1}'
        $remoteHost = $rs.GetType().GetProperty('Host', 60).GetValue($rs)
        $remoteHost.UI.Write($args[0])
        $remoteHost.UI.ReadLineAsSecureString()
    }).AddArgument($sudoPrompt)

    $output = $ps.Invoke()

    if ($output) {
        $pass = [PSCredential]::new('noop', $output[0]).GetNetworkCredential().Password
        return $pass
    }
} finally {
    if ($null -ne $ps) {
        $ps.Dispose()
    }

    if ($null -ne $rs) {
        $rs.Dispose()
    }
}
'@ -f ($pid, [Runspace]::DefaultRunspace.InstanceId)

    chmod +x $tempPath
    $env:SUDO_ASKPASS = $tempPath
}

It still needs to solve the fact that you need to call sudo with sudo -A but it at least sets up the environment properly.

@awakecoding
Copy link
Contributor

@TylerLeonhardt @jborean93 a module could be suitable to get something with older versions of PowerShell, but I think we should consider a built-in solution that comes with PowerShell, and not externally distributed or added on top.

@jborean93 is correct when he says that wrapping the command inside PowerShell would only work when calling "sudo" from PowerShell and wouldn't fix the issue of non-PowerShell scripts or native programs that call sudo directly. Of course, there is the issue of existing scripts that call "sudo" without "sudo -A", but this is still something that can be worked with. For instance, you can call sudo a first time to get prompted and run the unmodified script, the second sudo won't trigger the prompt because of the sudo cache, etc. We can also look into adding the sudo alias in bash, or look into advanced sudo configuration options. In any case, if sudo -A works, it would be a zillion times better than the current state of things.

As for wrapping and cleaning up afterwards, let's just look at the alternative: a guaranteed broken sudo when called from a PowerShell remoting session. I say we should automatically modify the environment to set SUDO_ASKPASS to point to a "pwsh-askpass" program in the PowerShell remoting server. As for the pwsh-askpass program itself, rather than distribute it as an external module, it should probably be part of the distributed PowerShell files.

The first issue we face is that SUDO_ASKPASS works with an executable, and not an executable with a parameter. The ideal solution would be to add an "-AskPass" parameter to the pwsh executable, such that the automatic SUDO_ASKPASS injection would point to the same PowerShell executable as the current PowerShell server. Here's the trick to make it work: just make a "pwsh-askpass" relative symbolic link to make it point to its corresponding "pwsh" executable. In the pwsh executable, all we would need to is inspect argv[0] which contains the executable name. When called through the pwsh-askpass symlink, argv[0] would contain "pwsh-askpass" instead of pwsh, making it easy to run pwsh as if it was called with the -AskPass parameter. I should note that PowerShell $arg[0] is the first parameter is not the executable, but in the pwsh executable I am sure we can extract the same information as it is normally available in C.

SUDO_ASKPASS is not something that is set in most cases, so I suggest we set it automatically unless it is already set, making it possible to override through some global system configuration.

As for helper environment variables to let pwsh-askpass find the parent pwsh to attach to, PowerShell should simply be modified to create and set those environment variables by default. We should take special care of setting the PID for the right process, which I understand should be the one containing the PowerShell remoting server, not some nested pwsh session inside a PowerShell remoting server.

I suggest the following names for the automatic environment variables to set that would be used by pwsh-askpass:
PWSH_ASKPASS_PROCESS_ID
PWSH_ASKPASS_RUNSPACE_ID

Also, even if we can make a working pwsh-askpass script, I suggest we drop the .ps1 extension because we don't necessarily wish it to remain a script. All you need is to make it executable and add the following line at the beginning:

#!/usr/bin/env pwsh

However, I would rather have pwsh-askpass point to pwsh -AskPass, and implement askpass inside pwsh. Maybe we could plan this for PowerShell 7.2, and make a simple pwsh-askpass script that does best effort detection for PWSH_ASKPASS_PROCESS_ID and PWSH_ASKPASS_RUNSPACE_ID. The script could be installed globally on the system, and modifications to the OpenSSH server configuration could be used to set SUDO_ASKPASS in the PowerShell remoting environment by default. This way we have something that works right now, and it would become a built-in feature in PowerShell 7.2.

@TylerLeonhardt
Copy link
Member

TylerLeonhardt commented Nov 29, 2020

Like a lot of things we consider to be the main package, if we can have it on the Gallery first, that is the first step.

Actually, the perfect model for such a function would be:
https://www.powershellgallery.com/packages/Microsoft.PowerShell.RemotingTools/0.1.0

@SteveL-MSFT @PaulHigin where is that repo?

This module contains remoting tool cmdlets.

Enable-SSHRemoting cmdlet:

PowerShell SSH remoting was implemented in PowerShell 6.0 but requries SSH (client) and SSHD (service) components
to be installed. In addition the sshd_config configuration file must be updated to define a PowerShell endpoint
as a subsystem. Once this is done PowerShell remoting cmdlets can be used to establish a PowerShell remoting
session over SSH that works across platforms.

$session = New-PSSession -HostName LinuxComputer1 -UserName UserA -SSHTransport

There are a number of requirements that must be satisfied for PowerShell SSH based remoting:
a. PowerShell 6.0 or greater must be installed on the system.
Since multiple PowerShell installations can appear on a single system, a specific installation can be selected.
b. SSH client must be installed on the system as PowerShell uses it for outgoing connections.
c. SSHD (ssh daemon) must be installed on the system for PowerShell to receive SSH connections.
d. SSHD must be configured with a Subsystem that serves as the PowerShell remoting endpoint.

The Enable-SSHRemoting cmdlet will do the following:
a. Detect the underlying platform (Windows, Linux, macOS).
b. Detect an installed SSH client, and emit a warning if not found.
c. Detect an installed SSHD daemon, and emit a warning if not found.
d. Accept a PowerShell (pwsh) path to be run as a remoting PowerShell session endpoint.
Or try to use the currently running PowerShell.
e. Update the SSHD configuration file to add a PowerShell subsystem endpoint entry.

If all of the conditions are satisfied then PowerShell SSH remoting will work to and from the local system.

@awakecoding
Copy link
Contributor

awakecoding commented Nov 30, 2020

@TylerLeonhardt totally agree, I think we should make it available as a separate component in a first step, then consider including it in the main package. On the long run, I do think this is something that should be built-in to PowerShell, it looks a bit odd to have to install a separate package to get sudo to work in a PowerShell remoting session, which is something most users would expect to work out of the box.

I suggest we make a first pwsh-askpass executable as a PowerShell script that would do best-effort detection of PWSH_ASKPASS_PROCESS_ID and PWSH_ASKPASS_RUNSPACE_ID when not available. For my own usage I think I would just "install" it manually in /usr/bin/pwsh-askpass and set SUDO_ASKPASS to 'pwsh-askpass' in my OpenSSH server environment. Once this script-based pwsh-askpass solution has had the chance of being used by some people, we could plan for possible inclusion in the main pwsh executable.

Do this sound like a good plan?

@TylerLeonhardt
Copy link
Member

TylerLeonhardt commented Nov 30, 2020

@jborean93 do you want to add what you have to this module?

https://github.com/PowerShell/Modules/tree/master/Modules/Microsoft.PowerShell.RemotingTools

Then we can start getting feedback.

GitHub
Contribute to PowerShell/Modules development by creating an account on GitHub.

@thukk
Copy link

thukk commented Dec 2, 2020

Thanks for looking into this. Yes, PowerShell remoting does now support passing SecureString objects over all platforms, but unfortunately was only added to 7.1+ versions.

I am not worried about prompting for sudo password over a remote session, that can be handled with remote host calls, and probably an update to the protocol (PSRP). My main concern was how to interface with sudo, and it looks like @awakecoding 'AskPass' is the mechanism to use. It would be nice if there was some sort of API hook, but the above PoC may be workable.

So, Since PS 7.0.3 is LTS (support lasts longer than 7.1), how can those of us that use/require an LTS version utilize sudo in a PSSession? Since security is of utmost importance, the script above that utilizes Readline() is not preferred.

@TylerLeonhardt
Copy link
Member

TylerLeonhardt commented Dec 2, 2020

the script above that utilizes Readline() is not preferred.

Why is that not preferred? I don't see how it would work without that.

@jborean93
Copy link
Collaborator

@TylerLeonhardt 7.1+ can use ReadLineAsSecureString which means the inputted characters are not echo'd back in the PSHost. Unfortunately older versions don't support secure strings over PSRemoting on non-Windows hosts so 7.0 is stuck with just ReadLine.

@TylerLeonhardt
Copy link
Member

Ahh that's right. I forgot about that fix. Also it's too complex to backport to 7.0 so unfortunately you are out of luck. Maybe we could "fake it" with reading characters one at a time and using some vt100 to clear the character typed... But that sounds so painful.

@jborean93
Copy link
Collaborator

jborean93 commented Dec 2, 2020

The other issue is that the types of calls you can make over a remote PSHost is limited. You are limited to just the ones listed at https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-psrp/ddd2a4d1-797d-4d73-8372-7a77a62fb204. Any of the methods that return a secure string will be out of luck with 7.0 :( Maybe you could have some sort of complex manual buffer manager at the RawUI layer but honestly I have no desire to investigate this :)

For people on 7.0 they could just do 'my password' | sudo -S something in PowerShell to cache your sudo credential so subsequent calls don't prompt you for it. Not ideal but it's what we have to work with.

This data type represents a method to be executed on a host. This data type is an enum (as specified in section 2.2.5.2.7) based on the default

@thukk
Copy link

thukk commented Dec 2, 2020

For people on 7.0 they could just do 'my password' | sudo -s something in PowerShell to cache your sudo credential so subsequent calls don't prompt you for it. Not ideal but it's what we have to work with.

Which would honestly be fine, if the following worked (which it doesn't).

$creds = Get-Credential
$session = New-PSSession -hostname Workstation1 -Username foo -SSHTransport
Invoke-Command -Session $session {param($creds) Invoke-Expression "echo $creds.password | sudo -S whoami"} -Argumentlist $creds

In 7.0, I cannot find a single way to pass secure strings to a PSSession, so scripting a sudo command is not possible. That sound about right?

Outside of a PSSession, it is possible to run something like ssh -t foo@Workstation1 'sudo whoami' and be prompted for 2 passwords, but it would be nice to do this within the confines of PSSession in 7.0.

@jborean93
Copy link
Collaborator

jborean93 commented Dec 2, 2020

Which would honestly be fine, if the following worked (which it doesn't).

That's because you are trying to send a secure string across which doesn't work on non-Windows hosts until 7.1. If the password was plaintext like so then it would work

$creds = Get-Credential
$sudoPass = $creds.GetNetworkCredential().Password
$session = New-PSSession -hostname Workstation1 -Username foo -SSHTransport

Invoke-Command -Session $session {
    param(
        [String]
        $SudoPass
    )

    $null = $SudoPass | sudo -S whoami
    if ($LastExitCode -ne 0) {
        Write-Error -Message "Failed to cache sudo password"
        return
    }

    # Now you have cached your sudo password you should be able to call it normally (up to whatever
    # timeout you have configured)
    sudo whoami
} -Argumentlist $sudoPass

Note this is not tested and it may require some better logic to check for failures but it should work. I will agree it's also not good to send passwords as plaintext across the wire but at least SSH encrypts the traffic. There's nothing that can be done about this unless you are on 7.1+ as we've mentioned. Even then on 7.1+ the SecureString will not be encrypted in memory on the remote process due to how SecureStrings work on non-Windows hosts. The 2 benefits 7.1 provides are:

  • SecureStrings are encrypted with a unique session key when traversing the wire. If someone was able to decrypt or monitor the plaintext SSH packets then the password will still be encrypted
  • You can use the PSHost SecureString prompts as we've mentioned before

It's up to the PowerShell team to backport the changes in #11185. I have no idea what the general policy is for this for this project so I can't really comment on it more.

Also your example had Invoke-Expression, that is not needed at all. You typically don't need to use iex to call a native binary as all iex does is runs the specified string as a PowerShell command which you already have.

@TylerLeonhardt
Copy link
Member

TylerLeonhardt commented Dec 2, 2020

@jborean93 in your example here you do:

​# Parent is sudo, grandparent is the pwsh process​
​$parentPid = (Get-Process -Id {0}).Parent.Parent.Id

Where that {0} will be formatted as $pid of the process that called this cmdlet.

Do you still need to do the .Parent.Parent.Id?

@jborean93
Copy link
Collaborator

Good catch, that should just be $parentPid = {0} or $parentPid = $env:SOMETHING. Was a leftover when I was just getting the grandparent PID which wouldn't work in all situations.

@TylerLeonhardt
Copy link
Member

@jborean93 do you have interest in contributing that cmdlet to the RemotingTools module so we can start getting validation? Your own separate module would also be totally cool.

@jborean93
Copy link
Collaborator

I would be interested but I don't have any spare time in the current week. I would probably only be able to work on it properly in about 2 weeks or so. People are more than welcome to take what I have and work on it if I'm taking too long :).

@IanEMartin
Copy link

Haven't seen any movement on this but see it as still open. I just started trying to manage *nix systems with remote PS sessions and this is a definite blocker.

@microsoft-github-policy-service microsoft-github-policy-service bot added the Resolution-No Activity Issue has had no activity for 6 months or more label Nov 16, 2023
@mcx808
Copy link

mcx808 commented Nov 16, 2023

@PaulHigin despite the lack of updates to this issue, I just tested again on pwsh 7.3.9 running on Debian 11 & 12. Still doesn't work when an interactive password is required but it does work with passwordless sudo, and you can workaround by piping a securestring into the sudo command (I don't remember if this was possible before).

example

[admin@test-deb11]: PS /home/admin> $pw = Read-Host -AsSecureString
WARNING: A script or application on the remote computer TEST-DEB11 is asking to read a line securely. Enter sensitive information, such as your credentials, only if you trust the remote computer and the application or script that is requesting it.
*******
[admin@test-deb11]: PS /home/admin> $pw | ConvertFrom-SecureString -AsPlainText | sudo -S cat /proc/cpuinfo
  • Sudo version is 1.9.5p2

Copy link
Contributor

This issue has been marked as "No Activity" as there has been no activity for 6 months. It has been closed for housekeeping purposes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Resolution-No Activity Issue has had no activity for 6 months or more Size-MultipleWeeks WG-Remoting PSRP issues with any transport layer
Projects
Status: Done
Development

No branches or pull requests

9 participants