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