1 module server;
2 version(Windows):
3 import sspi;
4 import std.socket : Socket;
5 import core.sys.windows.ntsecpkg : SECURITY_NATIVE_DREP;
6 
7 enum BackLog = 10;
8 
9 //  Port of Microsoft example for server-side SSPI Windows Sockets program.
10 
11 int main(string[] args)
12 {
13 	import std.conv : to;
14 	import std.stdio : writefln;
15 
16 	ushort serverPort = (args.length > 1) ? args[1].to!ushort : 9000.to!ushort;
17 	auto serverAuth = ServerAuth(); // "Negotiate", ServerAuth.DefaultSecurityContextFlags, SECURITY_NATIVE_DREP);
18 	serverAuth.setup();
19 	auto maxMessageSize = serverAuth.packageInfo.cbMaxToken;
20 	ubyte[] inBuf = new ubyte[maxMessageSize];
21 	ubyte[] outBuf = new ubyte[maxMessageSize];
22 
23 
24 	//-----------------------------------------------------------------   
25 	//  Start looping for clients.
26 
27 	while(true)
28 	{
29 		writefln("Waiting for client to connect...");
30 
31 		//  Make an authenticated connection with client.
32 		auto socket = serverAuth.acceptAuthSocket(serverPort);
33 		auto securityPackageContextSizes = queryContextAttributes!SecPkgContext_Sizes(&serverAuth.context,SecPackageAttribute.sizes);
34 		//----------------------------------------------------------------
35 		//  The following values are used for encryption and signing.
36 
37 		auto cbMaxSignature = securityPackageContextSizes.cbMaxSignature;
38 		auto cbSecurityTrailer = securityPackageContextSizes.cbSecurityTrailer;
39 
40 		auto securityPackageNegInfo = queryContextAttributes!SecPkgContext_NegotiationInfoW(&serverAuth.context,SecPackageAttribute.negotiationInfo);
41 		writefln("Package Name: %s", securityPackageNegInfo.packageInfo.Name);
42 		
43 		// impersonate the client
44 		auto userName = serverAuth.impersonate();
45 		writefln("Impersonation worked.");
46 		writefln("Client connected as: %s",userName);
47 
48 		// Revert to self.
49 		serverAuth.revertImpersonate();
50 		writefln("Reverted to self.");
51 
52 		// Send the client an encrypted message.
53 		auto message = "This is your server speaking";
54 		auto encryptedMessage = serverAuth.encrypt(message);
55 
56 		//-----------------------------------------------------------------   
57 		//  Send the encrypted data to client.
58 
59 		socket.sendBytes(encryptedMessage);
60 		writefln(" %s encrypted bytes sent.", encryptedMessage.length);
61 		serverAuth.dispose();
62 		serverAuth = ServerAuth("Negotiate", ServerAuth.DefaultSecurityContextFlags, SECURITY_NATIVE_DREP);
63 		serverAuth.setup();
64 	}
65 
66 	//writefln("Server ran to completion without error.");
67 }
68 
69 Socket acceptAuthSocket(ref ServerAuth server, ushort serverPort)
70 {
71 	import std.socket : getAddressInfo, AddressFamily, Socket, InternetAddress;
72 	import std.algorithm : filter;
73 	import std.array : array;
74 	import std.range : front;
75 	import std.exception : enforce;
76 	import std.conv : to;
77 
78     //  Lookup the server's address.
79     auto addressInfos = getAddressInfo("0.0.0.0")
80 						.filter!(info => info.family == AddressFamily.INET)
81 						.array;
82 
83 	auto address = new InternetAddress("0.0.0.0", serverPort);
84 
85     //  Create the socket.
86     Socket socket = new Socket(addressInfos.front);
87 	socket.bind(address);
88 
89 	// Listen
90 	socket.listen(BackLog);
91 	auto client = socket.accept();
92 	socket.close();
93 
94     auto messageResult = server.authorize();
95 	enforce(messageResult[0] == SecurityStatus.okay);
96 	auto message = messageResult[1];
97     client.sendMessage(message);
98 	message = socket.receiveMessage().idup;
99 	auto result = server.authorize(message);
100 	enforce(result[0] == SecurityStatus.okay, result[0].to!string);
101 	client.sendMessage(result[1]);
102     return client;
103 }
104 
105 
106 void printHexDump(const(ubyte)[] buf)
107 {
108 	import std.stdio : writefln;
109 	import std.format : format;
110 
111     size_t i,count,index;
112     char[] rgbDigits="0123456789abcdef".dup;
113     char[100] rgbLine;
114     char cbLine;
115 	auto length = buf.length;
116 	char* buffer = cast(char*)buf.ptr;
117 
118     for(index = 0; length; length -= count, buffer += count, index += count) 
119     {
120         count = (length > 16) ? 16:length;
121 
122         rgbLine = format!"%s4.4x  "(index);
123         cbLine = 6;
124 
125         for(i=0;i<count;i++) 
126         {
127             rgbLine[cbLine++] = rgbDigits[buffer[i] >> 4];
128             rgbLine[cbLine++] = rgbDigits[buffer[i] & 0x0f];
129             if(i == 7) 
130             {
131                 rgbLine[cbLine++] = ':';
132             } 
133             else 
134             {
135                 rgbLine[cbLine++] = ' ';
136             }
137         }
138         for(; i < 16; i++) 
139         {
140             rgbLine[cbLine++] = ' ';
141             rgbLine[cbLine++] = ' ';
142             rgbLine[cbLine++] = ' ';
143         }
144 
145         rgbLine[cbLine++] = ' ';
146 
147         for(i = 0; i < count; i++) 
148         {
149             if(buffer[i] < 32 || buffer[i] > 126) 
150             {
151                 rgbLine[cbLine++] = '.';
152             } 
153             else 
154             {
155                 rgbLine[cbLine++] = buffer[i];
156             }
157         }
158 
159         rgbLine[cbLine++] = 0;
160         writefln("%s", rgbLine);
161     }
162 }
163 
164 void sendMessage(Socket socket, const(ubyte)[] message)
165 {
166 	import std.conv : to;
167 	auto messageLength = message.length.to!ulong;
168 	socket.sendBytes((cast(ubyte*)&messageLength)[0..4]);
169 	socket.sendBytes(message);
170 }
171 
172 ubyte[] receiveMessage(Socket socket)
173 {
174 	import std.exception : enforce;
175 	import std.conv : to;
176 
177 	ubyte[4] messageLengthBuf;
178 	enforce(socket.receive(messageLengthBuf) ==4);
179 	auto messageLength = (*(cast(ulong*)(messageLengthBuf.ptr))).to!size_t;
180 	auto message = socket.receiveBytes(messageLength);
181 	return message;
182 }
183 
184 void sendBytes(Socket socket, const(ubyte)[] buf)
185 {
186     size_t numBytesRemaining = buf.length;
187 	size_t numBytesSent = 0;
188 
189     if (buf.length == 0)
190         return;
191 
192     while(numBytesRemaining > 0)
193     {
194         auto cbSent = socket.send(buf[numBytesSent .. $]);
195         numBytesSent += cbSent;
196         numBytesRemaining -= cbSent;
197     }
198 }
199 
200 ubyte[] receiveBytes(Socket socket, size_t messageLength = 0)
201 {
202 	import std.array : Appender;
203 	import std.conv : to;
204 
205 	Appender!(ubyte[]) ret;
206 	ubyte[1024] buf;
207     long cbRead, cbRemaining = messageLength;
208 
209     while (cbRemaining) 
210     {
211         cbRead = socket.receive(buf);
212 		ret.put(buf[0 .. cbRead.to!size_t]);
213         cbRemaining -= cbRead;
214     }
215     return ret.data;
216 }
217 
218