mirror of
https://github.com/neon443/ShhShell.git
synced 2026-03-11 13:26:16 +00:00
UI with custom host, username and pw
not hardcoded anymore set host port username and pw currently only password auth lol can get hostkeys replaced lots of fatalerrors with false returns
This commit is contained in:
@@ -12,23 +12,57 @@ import OSLog
|
|||||||
class SSHHandler: ObservableObject {
|
class SSHHandler: ObservableObject {
|
||||||
var session: ssh_session?
|
var session: ssh_session?
|
||||||
|
|
||||||
|
@Published var username: String
|
||||||
|
@Published var password: String
|
||||||
|
@Published var address: String
|
||||||
|
@Published var port: Int
|
||||||
|
|
||||||
private let logger = Logger(subsystem: "xy", category: "sshHandler")
|
private let logger = Logger(subsystem: "xy", category: "sshHandler")
|
||||||
|
|
||||||
init() {
|
init(
|
||||||
// session = ssh_new()
|
username: String = "",
|
||||||
// guard session != nil else { return }
|
password: String = "",
|
||||||
|
address: String = "",
|
||||||
|
port: Int = 22
|
||||||
|
) {
|
||||||
|
#if DEBUG
|
||||||
|
self.username = "root"
|
||||||
|
self.password = "root"
|
||||||
|
self.address = "localhost"
|
||||||
|
self.port = 2222
|
||||||
|
#endif
|
||||||
|
self.username = username
|
||||||
|
self.password = password
|
||||||
|
self.address = address
|
||||||
|
self.port = port
|
||||||
|
}
|
||||||
|
|
||||||
|
func getHostkey() {
|
||||||
|
var hostkey: ssh_key?
|
||||||
|
ssh_get_server_publickey(session, &hostkey)
|
||||||
|
|
||||||
|
var hostkeyB64: UnsafeMutablePointer<CChar>? = nil
|
||||||
|
if ssh_pki_export_pubkey_base64(hostkey, &hostkeyB64) == SSH_OK {
|
||||||
|
if let hostkeyB64 = hostkeyB64 {
|
||||||
|
print(String(cString: hostkeyB64))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func connect() -> Bool {
|
||||||
|
defer {
|
||||||
|
getHostkey()
|
||||||
|
getAuthMethods()
|
||||||
}
|
}
|
||||||
|
|
||||||
func connect() {
|
|
||||||
var verbosity: Int = 0
|
var verbosity: Int = 0
|
||||||
var port: Int = 2222
|
|
||||||
|
|
||||||
session = ssh_new()
|
session = ssh_new()
|
||||||
guard session != nil else {
|
guard session != nil else {
|
||||||
fatalError("no ssh session??!?!")
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
ssh_options_set(session, SSH_OPTIONS_HOST, "localhost")
|
ssh_options_set(session, SSH_OPTIONS_HOST, address)
|
||||||
ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity)
|
ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity)
|
||||||
ssh_options_set(session, SSH_OPTIONS_PORT, &port)
|
ssh_options_set(session, SSH_OPTIONS_PORT, &port)
|
||||||
|
|
||||||
@@ -36,49 +70,42 @@ class SSHHandler: ObservableObject {
|
|||||||
if status != SSH_OK {
|
if status != SSH_OK {
|
||||||
logger.critical("connection not ok: \(status)")
|
logger.critical("connection not ok: \(status)")
|
||||||
logSshGetError()
|
logSshGetError()
|
||||||
fatalError()
|
return false
|
||||||
}
|
}
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func disconnect() {
|
func disconnect() {
|
||||||
guard session != nil else { fatalError("no ssession") }
|
guard session != nil else {
|
||||||
|
print("cant disconnect when im not connected")
|
||||||
|
return
|
||||||
|
}
|
||||||
ssh_disconnect(session)
|
ssh_disconnect(session)
|
||||||
|
ssh_free(session)
|
||||||
}
|
}
|
||||||
|
|
||||||
func hardcodedAuth() {
|
func testExec() -> Bool {
|
||||||
var hostkey: ssh_key?
|
if ssh_is_connected(session) == 0 {
|
||||||
ssh_get_server_publickey(session, &hostkey)
|
if !connect() {
|
||||||
if let hostkey = hostkey {
|
return false
|
||||||
print("hostkey \(hostkey)")
|
|
||||||
}
|
|
||||||
|
|
||||||
let password = "root"
|
|
||||||
|
|
||||||
let rc = ssh_userauth_password(session, "root", password)
|
|
||||||
if rc != SSH_AUTH_SUCCESS.rawValue {
|
|
||||||
print("auth failure")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testExec() {
|
guard authWithPw() else { return false }
|
||||||
connect()
|
|
||||||
defer { disconnect();ssh_free(session) }
|
|
||||||
|
|
||||||
hardcodedAuth()
|
|
||||||
|
|
||||||
var status: CInt
|
var status: CInt
|
||||||
var buffer: [Int] = Array(repeating: 0, count: 256)
|
var buffer: [Int] = Array(repeating: 0, count: 256)
|
||||||
var nbytes: CInt
|
var nbytes: CInt
|
||||||
|
|
||||||
let channel = ssh_channel_new(session)
|
let channel = ssh_channel_new(session)
|
||||||
guard channel != nil else { fatalError("noChannel") }
|
guard channel != nil else { return false }
|
||||||
|
|
||||||
status = ssh_channel_open_session(channel)
|
status = ssh_channel_open_session(channel)
|
||||||
guard status == SSH_OK else {
|
guard status == SSH_OK else {
|
||||||
ssh_channel_free(channel)
|
ssh_channel_free(channel)
|
||||||
logger.critical("session opening error")
|
logger.critical("session opening error")
|
||||||
logSshGetError()
|
logSshGetError()
|
||||||
return
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
status = ssh_channel_request_exec(channel, "uptime")
|
status = ssh_channel_request_exec(channel, "uptime")
|
||||||
@@ -87,7 +114,7 @@ class SSHHandler: ObservableObject {
|
|||||||
ssh_channel_free(channel)
|
ssh_channel_free(channel)
|
||||||
logger.critical("session opening error")
|
logger.critical("session opening error")
|
||||||
logSshGetError()
|
logSshGetError()
|
||||||
return
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
nbytes = ssh_channel_read(
|
nbytes = ssh_channel_read(
|
||||||
@@ -103,7 +130,7 @@ class SSHHandler: ObservableObject {
|
|||||||
ssh_channel_free(channel)
|
ssh_channel_free(channel)
|
||||||
logger.critical("write error")
|
logger.critical("write error")
|
||||||
logSshGetError()
|
logSshGetError()
|
||||||
return
|
return false
|
||||||
}
|
}
|
||||||
nbytes = ssh_channel_read(channel, &buffer, UInt32(MemoryLayout.size(ofValue: Character.self)), 0)
|
nbytes = ssh_channel_read(channel, &buffer, UInt32(MemoryLayout.size(ofValue: Character.self)), 0)
|
||||||
}
|
}
|
||||||
@@ -113,44 +140,56 @@ class SSHHandler: ObservableObject {
|
|||||||
ssh_channel_free(channel)
|
ssh_channel_free(channel)
|
||||||
logger.critical("didnt read?")
|
logger.critical("didnt read?")
|
||||||
logSshGetError()
|
logSshGetError()
|
||||||
return
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
ssh_channel_send_eof(channel)
|
ssh_channel_send_eof(channel)
|
||||||
ssh_channel_close(channel)
|
ssh_channel_close(channel)
|
||||||
ssh_channel_free(channel)
|
ssh_channel_free(channel)
|
||||||
print("testExec succeeded")
|
print("testExec succeeded")
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func authWithPubkey() {
|
func authWithPubkey() -> Bool {
|
||||||
var status: CInt
|
var status: CInt
|
||||||
status = ssh_userauth_publickey_auto(session, nil, nil)
|
status = ssh_userauth_publickey_auto(session, nil, nil)
|
||||||
if status == SSH_AUTH_ERROR.rawValue {
|
if status == SSH_AUTH_ERROR.rawValue {
|
||||||
print("pubkey auth failed")
|
print("pubkey auth failed")
|
||||||
logSshGetError()
|
logSshGetError()
|
||||||
fatalError()
|
return false
|
||||||
}
|
}
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func authWithPw(_ username: String, _ password: String) {
|
func authWithPw() -> Bool {
|
||||||
var status: CInt
|
var status: CInt
|
||||||
status = ssh_userauth_password(session, username, password)
|
status = ssh_userauth_password(session, username, password)
|
||||||
guard status != SSH_ERROR else {
|
guard status != SSH_AUTH_SUCCESS.rawValue else {
|
||||||
print("ssh pw auth error")
|
print("ssh pw auth error")
|
||||||
logSshGetError()
|
logSshGetError()
|
||||||
return
|
return false
|
||||||
}
|
}
|
||||||
|
print("auth success")
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func authWithKbInt() {
|
func authWithKbInt() -> Bool {
|
||||||
var status: CInt
|
var status: CInt
|
||||||
status = ssh_userauth_kbdint(session, nil, nil)
|
status = ssh_userauth_kbdint(session, nil, nil)
|
||||||
while status == SSH_AUTH_INFO.rawValue {
|
while status == SSH_AUTH_INFO.rawValue {
|
||||||
let name, instruction: String
|
let name, instruction: String
|
||||||
var nprompts: CInt
|
var nprompts: CInt
|
||||||
|
|
||||||
name = UnsafeRawPointer(String(ssh_userauth_kbdint_getname(session)))
|
if let namePtr = ssh_userauth_kbdint_getname(session) {
|
||||||
instruction = String(ssh_userauth_kbdint_getinstruction(session))
|
name = String(cString: namePtr)
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if let instrPtr = ssh_userauth_kbdint_getinstruction(session) {
|
||||||
|
instruction = String(cString: instrPtr)
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
nprompts = ssh_userauth_kbdint_getnprompts(session)
|
nprompts = ssh_userauth_kbdint_getnprompts(session)
|
||||||
|
|
||||||
if name.count > 0 {
|
if name.count > 0 {
|
||||||
@@ -161,28 +200,47 @@ class SSHHandler: ObservableObject {
|
|||||||
}
|
}
|
||||||
for promptI in 0..<nprompts {
|
for promptI in 0..<nprompts {
|
||||||
let prompt: UnsafePointer<CChar>
|
let prompt: UnsafePointer<CChar>
|
||||||
var echo: CChar
|
var echo: CChar = 0
|
||||||
prompt = ssh_userauth_kbdint_getprompt(session, UInt32(promptI), &echo)
|
prompt = ssh_userauth_kbdint_getprompt(session, UInt32(promptI), &echo)
|
||||||
if echo != 0 {
|
if echo != 0 {
|
||||||
var buffer: [CChar] = Array(repeating: 0, count: 128)
|
var buffer: [CChar] = Array(repeating: 0, count: 128)
|
||||||
var ptr: UnsafeMutablePointer<CChar> = .init(mutating: buffer)
|
let ptr: UnsafeMutablePointer<CChar> = .init(mutating: buffer)
|
||||||
print(prompt)
|
print(prompt)
|
||||||
if fgets(&buffer, Int32(MemoryLayout.size(ofValue: buffer)), stdin) == nil {
|
if fgets(&buffer, Int32(MemoryLayout.size(ofValue: buffer)), stdin) == nil {
|
||||||
fatalError("autherror")
|
return false
|
||||||
}
|
}
|
||||||
if (ptr = strchr(buffer, 0)) != nil {
|
ptr.pointee = 0//prob fucked
|
||||||
ptr.pointee = "\0"
|
if ssh_userauth_kbdint_setanswer(session, UInt32(promptI), buffer) < 0 {
|
||||||
}
|
return false
|
||||||
if ssh_userauth_kbdint_setanswer(session, promptI, buffer) < 0 {
|
|
||||||
fatalError("autherr")
|
|
||||||
}
|
}
|
||||||
memset(&buffer, 0, buffer.count)
|
memset(&buffer, 0, buffer.count)
|
||||||
|
} else {
|
||||||
|
if (ssh_userauth_kbdint_setanswer(session, UInt32(promptI), &password) != 0) {
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
status = ssh_userauth_kbdint(session, nil, nil)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func authWithNone() -> Bool {
|
||||||
|
let status = ssh_userauth_none(session, nil)
|
||||||
|
if status == SSH_AUTH_SUCCESS.rawValue {
|
||||||
|
print("no security moment lol")
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getAuthMethods() {
|
||||||
|
var method: CInt
|
||||||
|
method = ssh_userauth_list(session, username)
|
||||||
}
|
}
|
||||||
|
|
||||||
func logSshGetError() {
|
func logSshGetError() {
|
||||||
logger.critical("\(String(describing: ssh_get_error(&self.session)))")
|
logger.critical("\(String(cString: ssh_get_error(&self.session)))")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,9 +9,11 @@ import SwiftUI
|
|||||||
|
|
||||||
@main
|
@main
|
||||||
struct ShhShellApp: App {
|
struct ShhShellApp: App {
|
||||||
|
@StateObject var sshHandler: SSHHandler = SSHHandler(username: "", password: "")
|
||||||
|
|
||||||
var body: some Scene {
|
var body: some Scene {
|
||||||
WindowGroup {
|
WindowGroup {
|
||||||
ContentView()
|
ContentView(handler: sshHandler)
|
||||||
}
|
}
|
||||||
.windowResizability(.contentMinSize)
|
.windowResizability(.contentMinSize)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,21 +8,41 @@
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct ContentView: View {
|
struct ContentView: View {
|
||||||
var sshHandler = SSHHandler()
|
@ObservedObject var handler: SSHHandler
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack {
|
VStack {
|
||||||
Image(systemName: "globe")
|
TextField("address", text: $handler.address)
|
||||||
.imageScale(.large)
|
.textFieldStyle(.roundedBorder)
|
||||||
.foregroundStyle(.tint)
|
TextField(
|
||||||
Text("Hello, world!")
|
"port",
|
||||||
Button("go") {
|
text: Binding(
|
||||||
sshHandler.testExec()
|
get: { String(handler.port) },
|
||||||
|
set: { handler.port = Int($0) ?? 22} )
|
||||||
|
)
|
||||||
|
.keyboardType(.numberPad)
|
||||||
|
.textFieldStyle(.roundedBorder)
|
||||||
|
TextField("username", text: $handler.username)
|
||||||
|
.textFieldStyle(.roundedBorder)
|
||||||
|
TextField("password", text: $handler.password)
|
||||||
|
.textFieldStyle(.roundedBorder)
|
||||||
|
|
||||||
|
Button("connect & auth") {
|
||||||
|
handler.connect()
|
||||||
|
handler.authWithPw()
|
||||||
|
}
|
||||||
|
Button("disconnect & free") {
|
||||||
|
handler.disconnect()
|
||||||
|
}
|
||||||
|
Button("testExec") {
|
||||||
|
handler.testExec()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#Preview {
|
#Preview {
|
||||||
ContentView()
|
ContentView(
|
||||||
|
handler: SSHHandler(username: "root", password: "root")
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user