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:
neon443
2025-06-06 21:14:11 +01:00
parent 8d68125b3f
commit 7adc2b7059
3 changed files with 141 additions and 61 deletions

View File

@@ -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)))")
} }
} }

View File

@@ -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)
} }

View File

@@ -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")
)
} }