1 #include "SSH.h"
2
3 namespace Upp {
4
5 #define LLOG(x) do { if(SSH::sTrace) RLOG("SshHosts: " << x); } while(false)
6
Add(const String & host,int port,const Info & info,const String & comment)7 bool SshHosts::Add(const String& host, int port, const Info& info, const String& comment)
8 {
9 return Add(Format("[%s]:%d", host, port), info, comment);
10 }
11
Add(const String & host,const Info & info,const String & comment)12 bool SshHosts::Add(const String& host, const Info& info, const String& comment)
13 {
14 ASSERT(ssh_session);
15 Clear();
16 bool b = handle &&
17 libssh2_knownhost_addc(
18 handle,
19 ~host,
20 nullptr,
21 ~info.key, info.key.GetLength(),
22 ~comment, comment.GetLength(),
23 info.type |
24 LIBSSH2_KNOWNHOST_TYPE_PLAIN |
25 LIBSSH2_KNOWNHOST_KEYENC_RAW,
26 nullptr
27 ) == 0;
28 return b ? b : Error();
29 }
30
Remove(SshHost * host)31 bool SshHosts::Remove(SshHost* host)
32 {
33 ASSERT(ssh_session);
34 Clear();
35 auto b = handle && libssh2_knownhost_del(handle, host) == 0;
36 return b ? b : Error();
37 }
38
Load(const String & filename)39 bool SshHosts::Load(const String& filename)
40 {
41 ASSERT(ssh_session);
42 Clear();
43 file_path = filename;
44 auto b = libssh2_knownhost_readfile(handle, ~file_path, LIBSSH2_KNOWNHOST_FILE_OPENSSH) >= 0;
45 return b ? b : Error();
46 }
47
Save()48 bool SshHosts::Save()
49 {
50 return SaveAs(file_path);
51 }
52
SaveAs(const String & filename)53 bool SshHosts::SaveAs(const String& filename)
54 {
55 ASSERT(ssh_session);
56 Clear();
57 auto b = handle && libssh2_knownhost_writefile(handle, ~filename, LIBSSH2_KNOWNHOST_FILE_OPENSSH) == 0;
58 return b ? b : Error();
59 }
60
Check(const String & host,int port)61 SshHosts::Info SshHosts::Check(const String& host, int port)
62 {
63 ASSERT(ssh_session);
64 Clear();
65 Info info;
66 if(handle) {
67 int type = 0;
68 size_t length = 0;
69 auto* p = libssh2_session_hostkey(ssh_session, &length, &type);
70 if(!p) {
71 Error();
72 info.status = LIBSSH2_KNOWNHOST_CHECK_FAILURE;
73 return pick(info);
74 }
75 info.status = libssh2_knownhost_checkp(
76 handle,
77 ~host,
78 port,
79 p,
80 length,
81 LIBSSH2_KNOWNHOST_TYPE_PLAIN |
82 LIBSSH2_KNOWNHOST_KEYENC_RAW,
83 nullptr
84 );
85 info.key.Set(p, length);
86 switch(type) {
87 case LIBSSH2_HOSTKEY_TYPE_RSA:
88 info.type = LIBSSH2_KNOWNHOST_KEY_SSHRSA;
89 break;
90 case LIBSSH2_HOSTKEY_TYPE_DSS:
91 info.type = LIBSSH2_KNOWNHOST_KEY_SSHDSS;
92 break;
93 case LIBSSH2_HOSTKEY_TYPE_UNKNOWN:
94 info.type = LIBSSH2_KNOWNHOST_KEY_UNKNOWN;
95 break;
96 default:
97 NEVER();
98 }
99 }
100 return pick(info);
101 }
102
GetHosts()103 Vector<SshHost*> SshHosts::GetHosts()
104 {
105 ASSERT(ssh_session);
106 Clear();
107 Vector<SshHost*> v;
108 SshHost *prev = nullptr, *next = nullptr;
109 int rc = libssh2_knownhost_get(handle, &prev, nullptr);
110 if(rc >= 0) {
111 v.Add(prev);
112 if(rc == 0)
113 while(rc < 1) {
114 rc = libssh2_knownhost_get(handle, &next, prev);
115 if(rc < 0) break;
116 v.Add(next);
117 prev = next;
118 }
119 }
120 if(rc < 0) Error();
121 return pick(v);
122 }
123
Error()124 bool SshHosts::Error()
125 {
126 ASSERT(ssh_session);
127 Buffer<char*> libmsg(256, 0);
128 int rc = libssh2_session_last_error(ssh_session, libmsg, nullptr, 0);
129 error.a = rc;
130 error.b = String(*libmsg);
131 LLOG("Failed. " << error.b);
132 return false;
133 }
134
SshHosts(SshSession & session)135 SshHosts::SshHosts(SshSession& session)
136 {
137 ASSERT(session.GetHandle());
138 ssh_session = session.GetHandle();
139 handle = libssh2_knownhost_init(ssh_session);
140 }
141
~SshHosts()142 SshHosts::~SshHosts()
143 {
144 if(ssh_session && handle)
145 libssh2_knownhost_free(handle);
146 }
147 }