1 module sspi.helpers;
2 
3 /+
4 	Helper classes for SSPI authentication via the win32security module.
5 	SSPI authentication involves a token-exchange "dance", the exact details
6 	of which depends on the authentication provider used.  There are also
7 	a number of complex flags and constants that need to be used - in most
8 	cases, there are reasonable defaults.
9 	These classes attempt to hide these details from you until you really need
10 	to know.  They are not designed to handle all cases, just the common ones.
11 	If you need finer control than offered here, just use the win32security
12 	functions directly.
13 +/
14 
15 /// Based on Roger Upole's sspi demos.
16 version(Windows):
17 import core.sys.windows.ntsecpkg;
18 import core.sys.windows.sspi;
19 import core.sys.windows.security;
20 import std.exception;
21 import sspi.defines;
22 import std.typecons:tuple;
23 import std.conv:to;
24 import std.utf:toUTF16z;
25 
26 bool secSuccess(SECURITY_STATUS status)
27 {
28 	return status >= 0;
29 }
30 
31 T queryContextAttributes(T)(SecHandle* context, SecPackageAttribute attribute)
32 {
33 	T ret;
34 	auto securityStatus = QueryContextAttributesW(context,attribute,cast(void*)&ret);
35 	enforce(securityStatus.secSuccess, (cast(SecurityStatus)securityStatus).to!string);
36 	return ret;
37 }
38 
39 uint decryptMessage(ref SecHandle context, ref SecBufferDesc message, uint messageSeqNo)
40 {
41 	uint fQOP;
42 	auto securityStatus = DecryptMessage(&context,&message,messageSeqNo,&fQOP);
43 	enforce(securityStatus.secSuccess, (cast(SecurityStatus)securityStatus).to!string);
44 	return fQOP;
45 }
46 
47 void encryptMessage(ref SecHandle context, uint fQOP, ref SecBufferDesc message, uint messageSeqNo)
48 {
49 	auto securityStatus = EncryptMessage(&context,fQOP, &message,messageSeqNo);
50 	enforce(securityStatus.secSuccess, (cast(SecurityStatus)securityStatus).to!string);
51 }
52 
53 void makeSignature(ref SecHandle context, uint fQOP, ref SecBufferDesc message, uint messageSeqNo)
54 {
55 	auto securityStatus = MakeSignature(&context,fQOP,&message,messageSeqNo);
56 	enforce(securityStatus.secSuccess, (cast(SecurityStatus)securityStatus).to!string);
57 }
58 
59 uint verifySignature(ref SecHandle context, ref SecBufferDesc message, uint messageSeqNo)
60 {
61 	uint pfQOP;
62 	auto securityStatus = VerifySignature(&context,&message,messageSeqNo,&pfQOP);
63 	enforce(securityStatus.secSuccess, (cast(SecurityStatus)securityStatus).to!string);
64 	return pfQOP;
65 }
66 
67 	
68 auto querySecurityPackageInfo(string packageName)
69 {
70 	PSecPkgInfoW ret;
71 	SecurityStatus securityStatus = cast(SecurityStatus) QuerySecurityPackageInfoW(cast(wchar*)packageName.toUTF16z,&ret);
72 	enforce(securityStatus.secSuccess, securityStatus.to!string);
73 	return ret;
74 }
75 
76 struct SecurityContextResult
77 {
78 	uint contextAttribute;
79 	TimeStamp expiry;
80 	SecurityStatus securityStatus;
81 	SecBufferDesc outputBufferDesc;
82 }
83 
84 auto initializeSecurityContext(ref CredHandle credentials, SecHandle* context, string targetName, uint fContextReq, ulong reserved1, uint targetDataRep, SecBufferDesc* input, ref SecBufferDesc outputBufferDesc)
85 {
86 	SecurityContextResult ret;
87 	ret.outputBufferDesc = outputBufferDesc;
88 	ret.securityStatus = cast(SecurityStatus) InitializeSecurityContextW(&credentials, context, cast(wchar*)targetName.toUTF16z, fContextReq, 0, targetDataRep,input,0,context,&ret.outputBufferDesc,&ret.contextAttribute,&ret.expiry);
89 	return ret;
90 }
91 
92 auto initializeSecurityContext(ref CredHandle credentials, SecHandle* context, string targetName, uint fContextReq, ulong reserved1, uint targetDataRep, ref SecBufferDesc input, ref SecBufferDesc outputBufferDesc)
93 {
94 	return initializeSecurityContext(credentials, context, targetName, fContextReq, reserved1, targetDataRep,&input,outputBufferDesc);
95 }
96 
97 auto initializeSecurityContextInitial(ref CredHandle credentials, SecHandle* context, string targetName, uint fContextReq, ulong reserved1, uint targetDataRep, ref SecBufferDesc outputBufferDesc)
98 {
99 	SecurityContextResult ret;
100 	ret.outputBufferDesc = outputBufferDesc;
101 	version(Trace)
102 	{
103 		import std.stdio;
104 		writefln("targetName: %s",targetName);
105 		writefln("fcontextReq: %s",fContextReq);
106 		writeln("targetDataRep: %s",targetDataRep);
107 	}
108 	ret.securityStatus = cast(SecurityStatus) InitializeSecurityContextW(&credentials,null,(targetName.length==0)? null : cast(wchar*)targetName.toUTF16z, fContextReq, 0, targetDataRep,null,0,context,&ret.outputBufferDesc,&ret.contextAttribute,&ret.expiry);
109 	return ret;
110 }
111 
112 void completeAuthToken(SecHandle* context, ref SecBufferDesc token)
113 {
114     auto securityStatus = CompleteAuthToken(context,&token);
115     enforce(securityStatus.secSuccess, (cast(SecurityStatus)securityStatus).to!string);
116 }
117