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 core.sys.windows.winbase : GetUserNameW;
21 import sspi.defines;
22 
23 bool secSuccess(SECURITY_STATUS status)
24 {
25 	return status >= 0;
26 }
27 
28 T queryContextAttributes(T)(SecHandle* context, SecPackageAttribute attribute)
29 {
30 	import std.exception : enforce;
31 	import std.conv:to;
32 	T ret;
33 	auto securityStatus = QueryContextAttributesW(context,attribute,cast(void*)&ret);
34 	enforce(securityStatus.secSuccess, (cast(SecurityStatus)securityStatus).to!string);
35 	return ret;
36 }
37 
38 uint decryptMessage(ref SecHandle context, ref SecBufferDesc message, uint messageSeqNo)
39 {
40 	import std.exception : enforce;
41 	import std.conv:to;
42 	uint fQOP;
43 	auto securityStatus = DecryptMessage(&context,&message,messageSeqNo,&fQOP);
44 	enforce(securityStatus.secSuccess, (cast(SecurityStatus)securityStatus).to!string);
45 	return fQOP;
46 }
47 
48 void encryptMessage(ref SecHandle context, uint fQOP, ref SecBufferDesc message, uint messageSeqNo)
49 {
50 	import std.exception : enforce;
51 	import std.conv:to;
52 	auto securityStatus = EncryptMessage(&context,fQOP, &message,messageSeqNo);
53 	enforce(securityStatus.secSuccess, (cast(SecurityStatus)securityStatus).to!string);
54 }
55 
56 void makeSignature(ref SecHandle context, uint fQOP, ref SecBufferDesc message, uint messageSeqNo)
57 {
58 	import std.exception : enforce;
59 	import std.conv:to;
60 	auto securityStatus = MakeSignature(&context,fQOP,&message,messageSeqNo);
61 	enforce(securityStatus.secSuccess, (cast(SecurityStatus)securityStatus).to!string);
62 }
63 
64 uint verifySignature(ref SecHandle context, ref SecBufferDesc message, uint messageSeqNo)
65 {
66 	import std.exception : enforce;
67 	import std.conv:to;
68 	uint pfQOP;
69 	auto securityStatus = VerifySignature(&context,&message,messageSeqNo,&pfQOP);
70 	enforce(securityStatus.secSuccess, (cast(SecurityStatus)securityStatus).to!string);
71 	return pfQOP;
72 }
73 
74 	
75 auto querySecurityPackageInfo(string packageName)
76 {
77 	import std.exception : enforce;
78 	import std.utf:toUTF16z;
79 	import std.conv:to;
80 	PSecPkgInfoW ret;
81 	SecurityStatus securityStatus = cast(SecurityStatus) QuerySecurityPackageInfoW(cast(wchar*)packageName.toUTF16z,&ret);
82 	enforce(securityStatus.secSuccess, securityStatus.to!string);
83 	return ret;
84 }
85 
86 struct SecurityContextResult
87 {
88 	uint contextAttribute;
89 	TimeStamp expiry;
90 	SecurityStatus securityStatus;
91 	SecBufferDesc outputBufferDesc;
92 }
93 
94 auto initializeSecurityContext(ref CredHandle credentials, SecHandle* context, string targetName, uint fContextReq, ulong reserved1, uint targetDataRep, SecBufferDesc* input, ref SecBufferDesc outputBufferDesc)
95 {
96 	import std.utf:toUTF16z;
97 	SecurityContextResult ret;
98 	ret.outputBufferDesc = outputBufferDesc;
99 	ret.securityStatus = cast(SecurityStatus) InitializeSecurityContextW(&credentials, context, cast(wchar*)targetName.toUTF16z, fContextReq, 0, targetDataRep,input,0,context,&ret.outputBufferDesc,&ret.contextAttribute,&ret.expiry);
100 	return ret;
101 }
102 
103 auto initializeSecurityContext(ref CredHandle credentials, SecHandle* context, string targetName, uint fContextReq, ulong reserved1, uint targetDataRep, ref SecBufferDesc input, ref SecBufferDesc outputBufferDesc)
104 {
105 	return initializeSecurityContext(credentials, context, targetName, fContextReq, reserved1, targetDataRep,&input,outputBufferDesc);
106 }
107 
108 auto initializeSecurityContextInitial(ref CredHandle credentials, SecHandle* context, string targetName, uint fContextReq, ulong reserved1, uint targetDataRep, ref SecBufferDesc outputBufferDesc)
109 {
110 	import std.utf:toUTF16z;
111 	SecurityContextResult ret;
112 	ret.outputBufferDesc = outputBufferDesc;
113 	version(Trace)
114 	{
115 		import std.stdio;
116 		writefln("targetName: %s",targetName);
117 		writefln("fcontextReq: %s",fContextReq);
118 		writeln("targetDataRep: %s",targetDataRep);
119 	}
120 	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);
121 	return ret;
122 }
123 
124 auto acceptSecurityContext(ref CredHandle credentials, SecHandle* context, SecBufferDesc* input, uint fContextReq, uint targetDataRep, SecHandle* newContext, ref SecBufferDesc outputBufferDesc)
125 {
126 	import std.utf:toUTF16z;
127 	SecurityContextResult ret;
128 	ret.outputBufferDesc = outputBufferDesc;
129 	ret.securityStatus = cast(SecurityStatus) AcceptSecurityContext(&credentials, context, input, fContextReq, targetDataRep,newContext,&ret.outputBufferDesc,&ret.contextAttribute,&ret.expiry);
130 	return ret;
131 }
132 
133 void completeAuthToken(SecHandle* context, ref SecBufferDesc token)
134 {
135 	import std.exception : enforce;
136 	import std.conv:to;
137     auto securityStatus = CompleteAuthToken(context,&token);
138     enforce(securityStatus.secSuccess, (cast(SecurityStatus)securityStatus).to!string);
139 }
140 
141 
142 void impersonateSecurityContext(SecHandle* context)
143 {
144 	import std.exception : enforce;
145 	import std.conv:to;
146 	auto securityStatus = ImpersonateSecurityContext(context);
147 	enforce(securityStatus.secSuccess, (cast(SecurityStatus)securityStatus).to!string);
148 }
149 
150 void revertSecurityContext(SecHandle* context)
151 {
152 	import std.exception : enforce;
153 	import std.conv:to;
154 	auto securityStatus = RevertSecurityContext(context);
155 	enforce(securityStatus.secSuccess, (cast(SecurityStatus)securityStatus).to!string);
156 }
157 
158 string getUserName()
159 {
160 	import std.format : format;
161 	import std.exception : enforce;
162 	import std.conv : to;
163 
164 	uint cbUserName;
165 	GetUserNameW(null,&cbUserName);
166 	enforce(cbUserName > 0, format!"unable to get username - cbUserName = %s"(cbUserName));
167 	auto ret = new wchar[cbUserName];
168 	auto result = GetUserNameW(ret.ptr,&cbUserName);
169 	enforce(result, format!"error getting username of length %s - status = %s"(cbUserName,result));	
170 	return ret.to!string;
171 }
172 
173 void freeCredentialsHandle(CredHandle* pCredentials)
174 {
175 	import std.format : format;
176 	import std.exception : enforce;
177 
178 	if (pCredentials is null)
179 		return;
180 	auto result = FreeCredentialsHandle(pCredentials);
181 	enforce(result == SEC_E_OK, format!"error freeing credentials handle for %s: %s"(*pCredentials, result));
182 }
183 
184 void deleteSecurityContext(SecHandle* pContext)
185 {
186 	import std.format : format;
187 	import std.exception : enforce;
188 
189 	if (pContext is null)
190 		return;
191 	auto result = DeleteSecurityContext(pContext);
192 	enforce(result == SEC_E_OK, format!"error deleting security context for %s: %s"(*pContext, result));
193 }
194