1 module client; 2 version(Windows): 3 import sspi; 4 import std.socket : Socket; 5 import core.sys.windows.ntsecpkg : SECURITY_NATIVE_DREP; 6 7 // Port of MS example of client-side program to establish an SSPI socket connection with a server and exchange messages. 8 9 10 // Define macros and constants. 11 enum BIG_BUFF = 2048; 12 13 bool SEC_SUCCESS(T)(T status) 14 { 15 return status >= 0; 16 } 17 18 enum g_usPort = 2000; 19 20 enum cbMaxMessage = 12000; 21 enum MessageAttribute = IscReq.confidentiality; 22 23 // #include <windows.h> 24 // #include <winsock.h> 25 // #include <stdio.h> 26 // #include <stdlib.h> 27 28 int main(string[] args) 29 { 30 import std.stdio : writefln, stderr; 31 import std.exception : enforce; 32 import std.format : format; 33 import std.conv : to; 34 35 auto user = getUserName(); 36 auto client = ClientAuth("NTLM",user); 37 string serverName = (args.length > 1) ? args[1] : "127.0.0.1"; 38 ushort serverPort = (args.length > 2) ? args[2].to!ushort : 9000; 39 40 auto socket = client.createAuthenticatedSocket(serverName, serverPort); 41 42 //-------------------------------------------------------------------- 43 // An authenticated session with a server has been established. 44 // Receive and manage a message from the server. 45 // First, find and display the name of the negotiated 46 // SSP and the size of the signature and the encryption 47 // trailer blocks for this SSP. 48 49 auto securityPackageNegotiationInfo = queryContextAttributes!SecPkgContext_NegotiationInfoW(&client.context, SecPackageAttribute.negotiationInfo); 50 writefln("Package Name: %s", securityPackageNegotiationInfo.packageInfo.Name); 51 52 auto securityPackageAttrSizes = queryContextAttributes!SecPkgContext_Sizes(&client.context, SecPackageAttribute.sizes); 53 54 auto cbMaxSignature = securityPackageAttrSizes.cbMaxSignature; 55 auto cbSecurityTrailer = securityPackageAttrSizes.cbSecurityTrailer; 56 57 //-------------------------------------------------------------------- 58 // decrypt and display the message from the server. 59 60 auto data = socket.receiveBytes(); 61 62 writefln("data before decryption including trailer (%s bytes):", data.length); 63 printHexDump(data); 64 cbSecurityTrailer = (*(cast(ulong*) data.ptr)).to!uint; 65 auto trailer = data[0 .. cbSecurityTrailer - 4]; 66 data = data [cbSecurityTrailer +4 .. $]; 67 auto message = client.decrypt(data.to!string, trailer.to!string); 68 69 writefln("The message from the server is \n %s", message); 70 71 client.dispose(); 72 return 0; 73 } 74 75 //-------------------------------------------------------------------- 76 // connectAuthSocket establishes an authenticated socket connection 77 // with a server and initializes needed security package resources. 78 79 Socket createAuthenticatedSocket(ref ClientAuth client, string serverName, ushort serverPort) 80 { 81 import std.socket : getAddressInfo, AddressFamily, Socket, InternetAddress; 82 import std.algorithm : filter; 83 import std.array : array; 84 import std.range : front; 85 86 //-------------------------------------------------------------------- 87 // Lookup the server's address. 88 89 auto addressInfos = getAddressInfo(serverName) 90 .filter!(info => info.family == AddressFamily.INET) 91 .array; 92 93 auto address = new InternetAddress(serverName, serverPort); 94 //-------------------------------------------------------------------- 95 // Create the socket. 96 97 Socket socket = new Socket(addressInfos.front); 98 socket.connect(address); 99 auto message = client.genClientContext([]); 100 socket.sendMessage(message); 101 message = socket.receiveMessage().idup; 102 auto result = client.genClientContext(message); 103 socket.sendMessage(result); 104 return socket; 105 } 106 107 108 auto genClientContext(ref ClientAuth client, const(ubyte)[] bufIn) 109 { 110 import std.exception : enforce; 111 import std.stdio : writefln; 112 import std.conv : to; 113 114 auto result = client.authorize(bufIn); 115 enforce(result[0] == SecurityStatus.okay, result.to!string); 116 writefln("Token buffer generated (%s bytes):", result[1].length); 117 printHexDump(result[1]); 118 return result[1]; 119 } 120 121 122 123 void printHexDump(const(ubyte)[] buf) 124 { 125 import std.format : format; 126 import std.stdio : writefln; 127 128 size_t i,count,index; 129 char[] rgbDigits = "0123456789abcdef".dup; 130 char[100] rgbLine; 131 char cbLine; 132 auto length = buf.length; 133 char* buffer = cast(char*)buf.ptr; 134 135 for(index = 0; length; 136 length -= count, buffer += count, index += count) 137 { 138 count = (length > 16) ? 16:length; 139 140 rgbLine = format!"%4.4x "(index); 141 cbLine = 6; 142 143 for(i=0;i<count;i++) 144 { 145 rgbLine[cbLine++] = rgbDigits[buffer[i] >> 4]; 146 rgbLine[cbLine++] = rgbDigits[buffer[i] & 0x0f]; 147 if(i == 7) 148 { 149 rgbLine[cbLine++] = ':'; 150 } 151 else 152 { 153 rgbLine[cbLine++] = ' '; 154 } 155 } 156 for(; i < 16; i++) 157 { 158 rgbLine[cbLine++] = ' '; 159 rgbLine[cbLine++] = ' '; 160 rgbLine[cbLine++] = ' '; 161 } 162 163 rgbLine[cbLine++] = ' '; 164 165 for(i = 0; i < count; i++) 166 { 167 if(buffer[i] < 32 || buffer[i] > 126) 168 { 169 rgbLine[cbLine++] = '.'; 170 } 171 else 172 { 173 rgbLine[cbLine++] = buffer[i]; 174 } 175 } 176 177 rgbLine[cbLine++] = 0; 178 writefln("%s", rgbLine); 179 } 180 } 181 182 void sendMessage(Socket socket, const(ubyte)[] message) 183 { 184 import std.conv : to; 185 auto messageLength = message.length.to!ulong; 186 socket.sendBytes((cast(ubyte*)&messageLength)[0..4]); 187 socket.sendBytes(message); 188 } 189 190 ubyte[] receiveMessage(Socket socket) 191 { 192 import std.conv : to; 193 import std.exception : enforce; 194 195 ubyte[4] messageLengthBuf; 196 enforce(socket.receive(messageLengthBuf) ==4); 197 size_t messageLength = (*(cast(ulong*)(messageLengthBuf.ptr))).to!size_t; 198 auto message = socket.receiveBytes(messageLength); 199 return message; 200 } 201 202 void sendBytes(Socket socket, const(ubyte)[] buf) 203 { 204 size_t numBytesRemaining = buf.length; 205 size_t numBytesSent = 0; 206 207 if (buf.length == 0) 208 return; 209 210 while(numBytesRemaining > 0) 211 { 212 auto cbSent = socket.send(buf[numBytesSent .. $]); 213 numBytesSent += cbSent; 214 numBytesRemaining -= cbSent; 215 } 216 } 217 218 ubyte[] receiveBytes(Socket socket, size_t messageLength = 0) 219 { 220 import std.array : Appender; 221 import std.conv : to; 222 223 Appender!(ubyte[]) ret; 224 ubyte[1024] buf; 225 long cbRead, cbRemaining = messageLength.to!long; 226 227 while(cbRemaining > 0) 228 { 229 cbRead = socket.receive(buf); 230 ret.put(buf[0 .. cbRead.to!size_t]); 231 cbRemaining -= cbRead; 232 } 233 return ret.data; 234 } 235 236