Giter VIP home page Giter VIP logo

swift-nio-ssh's Issues

ChannelError: operationUnsupported when executing commands from a daemon

Context

NIO SSH Commit Hash

36a4f6f4179ef5ebbeca501fc2125734b9f46290

Swift version

swift-driver version: 1.90.11.1 Apple Swift version 5.10 (swiftlang-5.10.0.13 clang-1500.3.9.4)
Target: arm64-apple-macosx14.0

uname -a

Darwin MacBook-Pro.local 23.2.0 Darwin Kernel Version 23.2.0: Wed Nov 15 21:55:06 PST 2023; root:xnu-10002.61.3~2/RELEASE_ARM64_T6020 arm64

Running Xcode 15.3 with macOS Sonoma 14.2.1 (23C71)

Problem

When using nio-ssh to execute ssh commands in a daemonized context (built executable launched using launchctl with a config in /Library/LaunchDaemons) a ChannelError (operationUnsupported) is thrown.

I'm unsure if this is a problem just with nio-ssh or nio in general. Could it be that certain network operations aren't permitted from within a daemon?

Any information/help on this matter is greatly appreciated!

Forum post: https://forums.developer.apple.com/forums/thread/749910

Reproduction

Reproduction can be found here: https://github.com/eliaSchenker/nio-ssh-daemon-issue/tree/main

To run the reproduction follow these steps:

  • Build using Xcode (Product > Build)
  • Find the executable in the build folder (Product > Show Build Folder in Finder)
  • Move the executable to /Library/PrivilegedHelperTools
  • Create a daemon configuration in /Library/LaunchDaemons/nio-ssh-daemon.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
	<dict>
		<key>Label</key>
		<string>nio-ssh-daemon</string>
		<key>ProgramArguments</key>
                 <array>
                 	<string>/Library/PrivilegedHelperTools/nio-ssh-daemon</string>
	    		<string>username:password@host</string>
			<string>ls -la</string>
                 </array>
		<key>KeepAlive</key>
		<true/>
		<key>ProcessType</key>
		<string>Interactive</string>
		<key>StandardOutPath</key>
		<string>/Library/Logs/nio-ssh-daemon.out.log</string>
		<key>StandardErrorPath</key>
		<string>/Library/Logs/nio-ssh-daemon.err.log</string>
	</dict>
</plist>

making sure to adjust the program arguments to include an host with username and password.

  • Load the daemon using
sudo launchctl load nio-ssh-daemon.plist
  • When opening Console.app, navigating to Log Reports and opening nio-ssh-daemon.out.log the logged error will be shown:
Creating bootstrap
Connecting channel
Creating child channel
Waiting for connection to close
Error in pipeline: operationUnsupported
An error occurred: commandExecFailed

If the executable is run manually without a daemon it will work correctly:

./nio.ssh-daemon username:password@host

The reproduction is a copy of the example in the repository (https://github.com/apple/swift-nio-ssh/tree/main/Sources/NIOSSHClient) with slight modifications to log errors instead of using try!.

RequestSuccessMessage currently only supports opening ports

As described in #17, there are a large variety of (possible) extensions and use cases aside from opening ports on a remote machine.

The RequestSuccessMessage type needs to be modified accordingly, so that other successful replies can be successfully received and processed.

Check inbound unprocessed packet sizes

There seem to be SSH-like servers on the internet that behave maliciously, with the intent of repelling malicious connections. They work by sending out an infinite version length or banner. I checked the recent code, but cannot find any length checks or tests. Although I doubt it's a common occurrence, I think it's best to add these checks with tests. I haven't determined a good maximum size yet, however. With some recommendations on that, I'll happily make a PR. I do think separate limits should exist for the pre/post KEX.

Authentication Failed using Private Key,Public Key

Hello
We are trying to connect our Mac and aws servers using the private key. but every time we got authentication failed.
Also, we have checked both keys on another application and it's working fine.so I think the problem is in the library. can you please help?

using this method

.byPublicKeyFromFile(username: self.username, password: "", publicKey: "", privateKey: pvtfilePath?.relativePath ?? "")

but not working can you please help us

Client remote port forwarding?

Hey guys, is it possible to implement remote/reverse port forwarding from the client side? Something similar as -R switch used in the ssh command: ssh -R 9090:localhost:8080 some.remoteserver.com

I'm currently using swift-nio to run a local web server + websocket in the iOS application, and I would like to expose it using the remote ssh server without any additional port forwarding configured on the router. Is it something like this even possible using swift-nio? Thanks!

How to validate host keys (i.e. how to access information about `NIOSSHPublicKey`)?

SwiftNIO SSH commit hash: 5d95eba

Context:
I'm trying to implement a NIOSSHClientServerAuthenticationDelegate that actually verifies the host key.

The problem:
Except for debug printing, I have not found any way to access any information about the supplied NIOSSHPublicKey.

Is there currently a way to access information about a NIOSSHPublicKey? (Apologies if I missed something obvious, I'm fairly new to swift).

System Information
$ swift --version
Apple Swift version 5.3.2 (swiftlang-1200.0.45 clang-1200.0.32.28)
Target: x86_64-apple-darwin19.6.0

$ uname -a
Darwin tim-mac.local 19.6.0 Darwin Kernel Version 19.6.0: Mon Aug 31 22:12:52 PDT 2020; root:xnu-6153.141.2~1/RELEASE_X86_64 x86_64 i386 MacBookPro12,1 Darwin

Missing Direct/Forwarded TCP IP Examples

Hello,

I was playing around with the library, and while the client example is good and shows how to establish a simple SSH connection, I can't quite figure out how to configure a direct TCP connection. I was able to change the example to open a channel of directTCPIP type, but it seems to be ignoring the originatorAddress, which I am assuming would be a port on my computer (just like when I call ssh -NL) but I am probbaly wrong.

I probably am not being able to figure it out as I haven't tried Swift NIO before, but an example on those kinds of connections would be helpful to me and probably to many others. :)

Thanks in advance!

Add better handling for SSH_MSG_UNIMPLEMENTED

We can receive SSH_MSG_UNIMPLEMENTED whenever we send a message the remote peer doesn't like. In almost all cases this is going to be an unrecoverable error for us, but we should validate we report the error sensibly and clearly.

How to use Swift Nio SSH?

Today I found this project, but hit the issue that I have no clue how to use the project. I believe it would help a lot to project, if there would be some "Get started" documentation, which would just describe basic scenarios, starting with:

  • How to connect to SSH server
  • How to authenticate
  • How to run command and get result

Is the SSH user name accessible by the ChannelHandler?

A server may care about which user has connected. I'm not seeing a path to connect the SSH user name to any of my handler code. I'm not even seeing it saved and available in SSHChildChannel or anything hanging off of it.

Unless I've missed something this will take some doing to add. Options include:

  • Adding a SSHChannelRequestEvent with a description of the user name which is sent first.

  • NIOSSHHandler() could get a new initializer which passes authentication information into the inboundChildChannelInitializer: equivalent.

Either of these presuppose that the user name is saved somewhere.

Child channels can not access their own peerMaxMessageSize

There does not appear to be any way for a child channel implementation to get access to the peerMaxMessageSize value derived from the SSH_MESSAGE_CHANNEL_OPEN message. This value is needed by some subsystems, such as SFTP, which are required to manually perform splitting of large data packets manually. In SFTP's case, offering an oversized value in a WriteFile request causes some servers to enter a wedged state waiting for data that will never arrive; without access to the channel's desired maximum message size, it must assume the worst (the specification-required minimum supported size of 32768 payload bytes), which is obviously less than ideal.

Support OpenSSH Keys

As I use SwiftNIO SSH, I need to provide the ability for my users to employ their existing private keys to connect to a remote host. As has been well-documented, SwiftCrypto lacks the ability to decrypt such keys when generated by OpenSSH.

Quoth @Lukasa in the Slack:

"If the user’s OpenSSH private key is passphrase protected then we cannot handle them in-tree at all. Because the way those keys are encrypted does not allow us to decrypt them with the APIs Swift Crypto provides. This is a ripe opportunity for someone to write a third-party extension to the library to handle this use-case."

This proposed extension to SwiftNIO SSH should solve two orthogonal problems:

  • Support RSA, which appears to be partially solved by @Joannis' PR: #62
  • Support ECDSA and ed25519 keys, by implementing a package that can parse the key format into the appropriate raw Swift Crypto format. "Basically, anything that does have access to an AES-CBC algorithm could do this. You can construct an SSH key from, say, a P256.Signing.PrivateKey object, and that ultimately can be derived from the OpenSSH private key format," writes @Lukasa.

Crypto primitives

The README says:

Modern cryptographic primitives only: Ed25519 and EDCSA over the major NIST curves (P256, P384, P521) for asymmetric cryptography, AES-GCM for symmetric cryptography, x25519 for key exchange

There's a typo: EDCSA should be ECDSA.

Also please consider support chacha20poly1305 for symmetric crypto as it performs much better for devices without hardware accelerated AES instructions and it is also the default used by modern versions of OpenSSH, the most popular SSH implementations on servers.

iOS: upload file to sshd server

Hi
I am looking from a way to upload file from my iOS app to an external ssh server.
I have tried swift-nio-ssh (NIOSSHClient example) from macos (not yet in iOS app) and I can connet to server and execute commands such as ls. Then I tried the put command and got "bash: put: command not found"... I think even though I can solve this on macos probably iOS will not have the put command. Well, my question is:
Is it possibel to use swift-nio-ssh, from an iOS app to upload a file to a ssh server not using bash commands but using class methods, such as childChannel.xx.yy.uploadfile("./abc.txt")?

Thank you very much
Alex

Minimum Deployment Target

MacOS
I found 10.15 is set as minimum deployment target... is it possible to built it for 10.10 ?

Third-Party Cryptographic Implementations

For implementing RSA support, which will not be landing in the main library as discussed, we'll need to support external implementations for at least public-private keys. I'd also recommend looking into the same for the symmetric encryption as seen in #48

There does not appear to be a way for a server to send an exit-status.

I see machinery for sending an SSH protocol "exit-status" SSHMessage, and it initializes from SSHChannelData (which I can send), but there doesn't seem to be any machinery to encode an "exit-status" in an SSHChannelData and get it through into a SSHMessage.channelRequest.

That looks to be the right way to send an exit-status, unless I'm missing something obvious.

So, is there a way I'm missing? Or maybe I should make a PR?

Cleanup once NIO adopts Sendable

Once NIO adopts Sendable conformances we should cleanup the following things:

  • Remove @preconcurrency from imports
  • Remove @unchecked from SSHChildChannel conformance

underlyingCoreCryptoError while creating NIOSSHPrivateKey

Hi,
I'm trying to setup a SSH tunnel in order to forward a remote port into my local device. I followed your PR #55 and I successfully implemented it into a brand new iOS project: I am able to forward a port using password authentication.

What I'm trying to do is performing a private key authentication. Due to the lack of the documentation, I'm going to ask you a few questions. Here's the code:

//ssh-keygen -t ecdsa -b 521 -m pem

let sshPrivateText = """
-----BEGIN EC PRIVATE KEY-----
row1
row2
row3
row4
row5
-----END EC PRIVATE KEY-----
"""
            
            let base64EncodedString:String = Data(sshPrivateText.utf8).base64EncodedString()
            let ecdsaPrivateKeyData:Data = Data(base64Encoded: base64EncodedString, options: .ignoreUnknownCharacters)!
            let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
            let key: NIOSSHPrivateKey?
            do {
                key = NIOSSHPrivateKey(p521Key: try .init(rawRepresentation: ecdsaPrivateKeyData))
            } catch let error {
                fatalError(error.localizedDescription)
            }

But I can't go further the NIOSSHPrivateKey constructor since the .init throws an error:

Fatal error: The operation couldn’t be completed. (CryptoKit.CryptoKitError error 0.): file /Users/user/XCode Projects/NioExample/NioExample/ContentView.swift, line 35
2020-12-13 12:57:48.397737+0100 NioExample[2711:69134] Fatal error: The operation couldn’t be completed. (CryptoKit.CryptoKitError error 0.): file /Users/user/XCode Projects/NioExample/NioExample/ContentView.swift, line 35
(lldb) 
▿ CryptoKitError
  ▿ underlyingCoreCryptoError : 1 element
    - error : -1

Also, I have another question. Why the minimum SDK level is iOS13? Could it be downgraded or something? It's a huge device cut! Will this project be included in cocoapods? I'm asking this because I'm going to integrate this script into a native Flutter plugin and it seems like Flutter projects are not compatibile with SwiftPM.

Thank you for this amazing project by the way!

NIOSSHClient gets stucked

Problem

When testing NIOSSHClient, I am always getting stucked indefinitely on childChannel wait() method. Could somebody help me understand what is the problem?

Findings

  • promise.FutureResult was created successfully, but my guess is, it was never met.
  • ExampleExecHandler was never activated and command was never executed.

Setup

  • Testing on M1 Macbook Pro with latest MacOS & XCode

Support keyboard-interactive authentication

While implementing 2-factor login in my app, I noticed that swift-nio-ssh is missing support for keyboard-interactive authentication. I can create a pull request to add it to the NIOSSHAvailableUserAuthenticationMethods: OptionSet and make the client recognize keyboard-interactive messages. However, I am concerned that this change may cause issues on the server-side. So I created this issue to ask if you have any plans to support keyboard-interactive authentication in the future.

NIOSSHPrivateKey from file/bytes

I don't know if I am missing something, is there a way to parse a private key file or private key data with a passphrase into a NIOSSHPrivateKey without knowing the type of private key you want to open?

Channel closes after 1 command / Executing multiple requests on the same channel

Hi everybody,

first all of all, I want to say a huge thanks for extending SwiftNIO to support SSH connections and removing the need of relying on external libraries for ssh on swift.

I'm currently working on a ssh client that can execute requests on a remote machine. Since the project already relies on SwiftNIO, I was happy to hear about NIOSSH and wanted to use it for handling the connection and requests.
I oriented myself closely on the examples provided in NIOSSHClient and initialised the channel and child channel like this:

let clientBootstrap = ClientBootstrap(group: group)
            .channelInitializer { channel in
                channel.pipeline.addHandlers([NIOSSHHandler(role: .client(.init(userAuthDelegate: InteractivePasswordPromptDelegate(username: self.username, password: self.password), serverAuthDelegate: AcceptAllKeysDelegate())), allocator: channel.allocator, inboundChildChannelInitializer: nil), ErrorHandler()])
            }
            .channelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR), value: 1)
            .channelOption(ChannelOptions.socket(SocketOptionLevel(IPPROTO_TCP), TCP_NODELAY), value: 1)
        
        self.channel = try clientBootstrap.connect(host: self.ipAdress, port: self.port).wait()
        
        let childChannel: Channel = try! channel!.pipeline.handler(type: NIOSSHHandler.self).flatMap { sshHandler in
            let promise = self.channel!.eventLoop.makePromise(of: Channel.self)
            sshHandler.createChannel(promise) { childChannel, channelType in
                guard channelType == .session else {
                    return self.channel!.eventLoop.makeFailedFuture(SSHClientError.invalidChannelType)
                }
                return childChannel.pipeline.addHandlers([ExecutionHandler(), ErrorHandler()])
            }
            return promise.futureResult
        }.wait()
        self.childChannel = childChannel

The ExecutionHandler that is passed to the childchannel's pipeline overrides func triggerUserOutboundEvent and triggers an internal outbound event that contains a SSHChannelRequestEvent.ExecRequest :

public func triggerUserOutboundEvent(context: ChannelHandlerContext, event: Any, promise: EventLoopPromise<Void>?) {
        guard let (buffer, responseHandler) = event as? (ByteBuffer, ((String, Int32) -> Void)?) else {
            promise?.fail(SSHError.invalidData)
            return
        }
        self.responseHandler = responseHandler
        let _ = context.triggerUserOutboundEvent(SSHChannelRequestEvent.ExecRequest(command: String(buffer: buffer), wantReply: false))
    }

This works fine for one request. But if i try to trigger multiple outbound events, i.e. send multiple SSHChannelRequestEvent.ExecRequest, it fails by returning inputClosed and the child channel is closed. This is problematic since it loses the state of the requests. If I wanted to change the directory with one request, the second one would start again in the root dir.
I am fairly new to SwiftNIO and NIOSSH, so I wanted to ask if this is a known problem or am I just using the framework wrong?
The READ.me states ...A session channel represents an invocation of a command. Does this mean a session is supposed to be closed after one command? If so, is there still a possibility to maintain the state of a request? For now I've been concatenating related commands together with command1 && command2 and executing them in one request. But this seems more like a hack to me.

Any help is greatly appreciated!

ssh -L

I am trying to use the codes from main.swift to do Local Port Forwarding but I am getting::
bind(descriptor:ptr:bytes:): Operation not permitted (errno: 1)

Can someone please help to do below SSH Cmd with Swift NIO SSH::
ssh -L 4944:localhost:4944 root@__IP__ -p 5544
I sucessfully made a channel but not very sure what to do next for Port Forwarding

I'm very new to Swift Nio, found it yesterday 😅

Key exchange should be initialized on handlerAdded as well

Sometimes we already have an established channel, for example,
one returned by establishing a tunneled connection. If this
is the case, then we cannot use it to start key exchange, since
it's only started when channel becomes active. In order to
support more use cases we should handle starting key exchange
when handler is added as well.

Crash in `SSHChildChannel`

SwiftNIO SSH commit hash: c56abab

Context

While writing Xcode tests in one of my project which uses swift-nio-ssh, I encountered a crash.
I reproduced it using the NIOSSHClient target.

  • The code is available in my fork
  • The crash happens when we force the closing of the channel while the command is running
  • The crash only appears when using a command which produces a long output such as yes \"long text\" | head -n 1000000\n
  • I only reproduced it when exchanging with the linked docker container. I'm using it in my automated tests.

Steps to reproduce

  1. Launch the ssh server: docker-compose -f ./docker/ssh-docker-compose.yaml up -d
  2. Run the modified NIOSSHClient target.
  3. Observe the crash in Xcode
* thread #2, name = 'NIO-ELT-0-#0', stop reason = Fatal error: Sent channel window adjust on channel in invalid state
    frame #0: 0x0000000193fe4ae8 libswiftCore.dylib`_swift_runtime_on_report
    frame #1: 0x00000001940825d4 libswiftCore.dylib`_swift_stdlib_reportFatalErrorInFile + 208
    frame #2: 0x0000000193c614b4 libswiftCore.dylib`closure #1 (Swift.UnsafeBufferPointer<Swift.UInt8>) -> () in closure #1 (Swift.UnsafeBufferPointer<Swift.UInt8>) -> () in Swift._assertionFailure(_: Swift.StaticString, _: Swift.String, file: Swift.StaticString, line: Swift.UInt, flags: Swift.UInt32) -> Swift.Never + 196
    frame #3: 0x0000000193c60210 libswiftCore.dylib`Swift._assertionFailure(_: Swift.StaticString, _: Swift.String, file: Swift.StaticString, line: Swift.UInt, flags: Swift.UInt32) -> Swift.Never + 308
  * frame #4: 0x00000001002cae7c NIOSSHClient`ChildChannelStateMachine.sendChannelWindowAdjust(message=(recipientChannel = 0, bytesToAdd = 8811376), self=NIOSSH.ChildChannelStateMachine @ 0x0000000101e040a8) at ChildChannelStateMachine.swift:432:13
...

Configuration

$ swift --version
swift-driver version: 1.75.2 Apple Swift version 5.8 (swiftlang-5.8.0.124.2 clang-1403.0.22.11.100)
Target: arm64-apple-macosx13.0

Operating system: macOS Ventura 13.2

Xcode version: 14.2

$ uname -a
Darwin MBP-de-Gaetan-Zanella 22.3.0 Darwin Kernel Version 22.3.0: Thu Jan 5 20:48:54 PST 2023; root:xnu-8792.81.2~2/RELEASE_ARM64_T6000 arm64

Simple SSH Client port forwarding

I am trying to figure out how to write a simple Swift code for running an ssh client port forwarding command. I am aware of [swift-nio-ssh] but am not sure how to use that in Xcode. Any suggestion?

NIOSSHClientUserAuthenticationDelegate Improvement Request: Result Reporting

The NIOSSHClientUserAuthenticationDelegate provides a single method, nextAuthenticationRequest, for providing offers for authenticating with a remote host. In the golden path, an auth request is successful and everyone is happy. However, in situations where the request fails, either because of incorrect credentials or an unexpected failure on the remote end, it would be useful for the delegate to receive a notification to that effect. As things stand now, the only way to know an offer fails is if the method is called again. That type of inference is something I'd rather not rely upon.

In my research of this repository, I came across NIOSSHUserAuthenticationOutcome; I wonder if using that here would be helpful?

NIOSSHError.keyExchangeNegotiationFailure

Hello, I am trying to SSH to a HPC server using this library, but trying to authenticate when connecting always gives me the above error. I have tried both password authentication and p521 key authentication to no avail.

Since I have been able to successfully use SwiftNIO SSH to execute a test command on another known server, I am sure my code runs correctly (it is also adapted from the NIOSSHClient example code from this repository). I am also able to SSH with a regular computer to the HPC server.

Running ssh -Q key on the HPC server gives the following:

ssh-ed25519
[email protected]
ssh-rsa
ssh-dss
ecdsa-sha2-nistp256
ecdsa-sha2-nistp384
ecdsa-sha2-nistp521
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]

which is exactly the same as on the test server I have been able to connect to, and includes ed25519. Any ideas what the problem could be?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.