1 module proxy; 2 3 import std.stdio; 4 import std.functional; 5 import std.format; 6 import std.string; 7 8 import libssh.session; 9 import libssh.channel; 10 import libssh.errors; 11 import libssh.server; 12 import libssh.poll; 13 14 enum auto USER = "myuser"; 15 enum auto PASSWORD = "mypassword"; 16 17 bool authentificated = false; 18 int tries = 0; 19 bool error = false; 20 SSHChannel chan = null; 21 string username; 22 GSSAPICreds clientCreds = 0; 23 24 AuthState authPassword(SSHSession session, string user, string password) { 25 stdout.writefln("Authenticating user %s pwd %s\n",user, password); 26 if (user == USER && password == PASSWORD) { 27 authentificated = true; 28 stdout.writefln("Authenticated"); 29 return AuthState.Success; 30 } 31 if (tries >= 3) { 32 stdout.writefln("Too many authentication tries"); 33 session.disconnect(); 34 error = true; 35 return AuthState.Denied; 36 } 37 tries++; 38 return AuthState.Denied; 39 } 40 41 version(LIBSSH_WITH_GSSAPI) { 42 AuthState authGSSAPIMic(SSHSession session, string user, string principal) { 43 clientCreds = session.gssapiGetCreds; 44 stdout.writefln("Authenticating user %s with gssapi principal %s",user, principal); 45 if (clientCreds !is null) { 46 stdout.writefln("Received some gssapi credentials"); 47 } else { 48 stdout.writefln("Not received any forwardable creds"); 49 } 50 stdout.writefln("authenticated"); 51 authentificated = true; 52 username = principal.dup; 53 return AuthState.Success; 54 } 55 } 56 57 bool ptyRequest(SSHChannel channel, string term, int width, int height, int pxWidth, int pxHeight) { 58 stdout.writeln("allocated terminal"); 59 return true; 60 } 61 62 bool shellRequest(SSHChannel channel) { 63 stdout.writeln("allocated shell"); 64 return true; 65 } 66 67 SSHChannel newSessionChannel(SSHSession session) { 68 if (chan !is null) { 69 return null; 70 } 71 chan = session.newChannel(); 72 chan.onPtyRequestCallback = toDelegate(&ptyRequest); 73 chan.onShellRequestCallback = toDelegate(&shellRequest); 74 return chan; 75 } 76 77 // TODO: options parsing 78 79 int main(string[] argv) { 80 scope(exit) sshFinalize(); 81 82 try { 83 auto sshBind = new SSHBind(); 84 scope(exit) sshBind.dispose(); 85 86 auto session = new SSHSession(); 87 scope(exit) session.dispose(); 88 89 sshBind.rsaKey = "sshd_rsa"; 90 91 // TODO: options parsing 92 sshBind.bindPort = 2222; 93 94 sshBind.listen(); 95 96 sshBind.accept(session); 97 98 session.serverAuthPasswordCallback = toDelegate(&authPassword); 99 session.serverChannelOpenRequestCallback = toDelegate(&newSessionChannel); 100 version(LIBSSH_WITH_GSSAPI) { 101 session.ServerAuthGSSAPIMicCallback = toDelegate(&authGSSAPIMic); 102 } 103 104 session.handleKeyExchange(); 105 version(LIBSSH_WITH_GSSAPI) { 106 session.authMethods = AuthMethod.Password | AuthMethod.GSSAPIMic; 107 } else { 108 session.authMethods = AuthMethod.Password; 109 } 110 111 auto mainLoop = new SSHEvent(); 112 scope(exit) mainLoop.dispose(); 113 mainLoop.addSession(session); 114 115 while (!(authentificated && chan !is null)) { 116 if (error) { 117 break; 118 } 119 120 mainLoop.doPoll(-1); 121 } 122 123 if (error) { 124 stdout.writeln("Error, exiting loop"); 125 return 1; 126 } else { 127 stdout.writeln("Authenticated and got a channel"); 128 } 129 if (clientCreds == 0) { 130 chan.write("Sorry, but you do not have forwardable tickets. Try again with -K\r\n"); 131 stdout.writeln("Sorry, but you do not have forwardable tickets. Try again with -K"); 132 session.disconnect(); 133 return 1; 134 } 135 136 chan.write(format("Hello %s, welcome to the Sample SSH proxy.\r\nPlease select your destination: ", 137 username)); 138 139 string host = ""; 140 int i = 0; 141 do { 142 char[2048] buf; 143 i = chan.read(buf, false); 144 if (i > 0) { 145 chan.write(buf[0 .. i]); 146 if (host.length + i < 128) { 147 host ~= buf[0 .. i]; 148 } 149 auto lfIndex = host.indexOf('\x0d'); 150 if (lfIndex >= 0) { 151 host = host[0 .. lfIndex]; 152 chan.write("\n"); 153 break; 154 } 155 } else { 156 stdout.writefln("Error: %s", session.lastError); 157 return 1; 158 } 159 } while (i > 0); 160 161 auto buf = format("Trying to connect to \"%s\"\r\n", host); 162 chan.write(buf); 163 stdout.write(buf); 164 165 auto clientSession = new SSHSession(); 166 scope(exit) clientSession.dispose(); 167 168 /* ssh servers expect username without realm */ 169 auto ptr = username.indexOf('@'); 170 if (ptr >= 0) { 171 username = username[0 .. ptr]; 172 } 173 174 clientSession.host = host; 175 clientSession.user = username; 176 version(LIBSSH_WITH_GSSAPI) { 177 clientSession.gssapiCreds = clientCreds; 178 } 179 clientSession.connect(); 180 181 auto rc = clientSession.userauthNone(null); 182 if (rc == AuthState.Success) { 183 stdout.writeln("Authenticated using method none"); 184 } else { 185 rc = clientSession.userauthGSSAPI(); 186 if (rc != AuthState.Success) { 187 stdout.writefln("GSSAPI Authentication failed: %s", clientSession.lastError); 188 return 1; 189 } 190 } 191 192 buf = "Authentication success\r\n"; 193 stdout.write(buf); 194 chan.write(buf); 195 clientSession.disconnect(); 196 session.disconnect(); 197 198 } catch (SSHException sshException) { 199 stderr.writefln("SSH exception. Code = %d, Message:\n%s\n", 200 sshException.errorCode, sshException.msg); 201 return -1; 202 } 203 return 0; 204 }