IdAuthenticationSSPI.pas 42 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322
  1. {
  2. $Project$
  3. $Workfile$
  4. $Revision$
  5. $DateUTC$
  6. $Id$
  7. This file is part of the Indy (Internet Direct) project, and is offered
  8. under the dual-licensing agreement described on the Indy website.
  9. (http://www.indyproject.org/)
  10. Copyright:
  11. (c) 1993-2005, Chad Z. Hower and the Indy Pit Crew. All rights reserved.
  12. }
  13. {
  14. $Log$
  15. }
  16. {
  17. Rev 1.3 6/11/2004 9:33:58 AM DSiders
  18. Added "Do not Localize" comments.
  19. Rev 1.2 13.1.2004 ã. 17:26:06 DBondzhev
  20. Added Domain property
  21. Rev 1.1 4/12/2003 10:24:04 PM GGrieve
  22. Fix to Compile
  23. Rev 1.0 11/14/2002 02:13:50 PM JPMugaas
  24. }
  25. unit IdAuthenticationSSPI;
  26. {
  27. Implementation of the NTLM authentication with SSPI
  28. Author: Alex Brainman
  29. Copyright: (c) Chad Z. Hower and The Winshoes Working Group.
  30. }
  31. {$DEFINE SET_ENCRYPT_IN_FT_WITH_GETPROCADDRESS_FUDGE}
  32. interface
  33. {$i IdCompilerDefines.inc}
  34. uses
  35. IdGlobal,
  36. IdAuthentication,
  37. IdCoder,
  38. Windows,
  39. SysUtils,
  40. IdSSPI;
  41. const
  42. SEC_E_OK = 0;
  43. {$EXTERNALSYM SEC_E_OK}
  44. SEC_E_INSUFFICIENT_MEMORY = HRESULT($80090300);
  45. {$EXTERNALSYM SEC_E_INSUFFICIENT_MEMORY}
  46. SEC_E_INVALID_HANDLE = HRESULT($80090301);
  47. {$EXTERNALSYM SEC_E_INVALID_HANDLE}
  48. SEC_E_UNSUPPORTED_FUNCTION = HRESULT($80090302);
  49. {$EXTERNALSYM SEC_E_UNSUPPORTED_FUNCTION}
  50. SEC_E_TARGET_UNKNOWN = HRESULT($80090303);
  51. {$EXTERNALSYM SEC_E_TARGET_UNKNOWN}
  52. SEC_E_INTERNAL_ERROR = HRESULT($80090304);
  53. {$EXTERNALSYM SEC_E_INTERNAL_ERROR}
  54. SEC_E_SECPKG_NOT_FOUND = HRESULT($80090305);
  55. {$EXTERNALSYM SEC_E_SECPKG_NOT_FOUND}
  56. SEC_E_NOT_OWNER = HRESULT($80090306);
  57. {$EXTERNALSYM SEC_E_NOT_OWNER}
  58. SEC_E_CANNOT_INSTALL = HRESULT($80090307);
  59. {$EXTERNALSYM SEC_E_CANNOT_INSTALL}
  60. SEC_E_INVALID_TOKEN = HRESULT($80090308);
  61. {$EXTERNALSYM SEC_E_INVALID_TOKEN}
  62. SEC_E_CANNOT_PACK = HRESULT($80090309);
  63. {$EXTERNALSYM SEC_E_CANNOT_PACK}
  64. SEC_E_QOP_NOT_SUPPORTED = HRESULT($8009030A);
  65. {$EXTERNALSYM SEC_E_QOP_NOT_SUPPORTED}
  66. SEC_E_NO_IMPERSONATION = HRESULT($8009030B);
  67. {$EXTERNALSYM SEC_E_NO_IMPERSONATION}
  68. SEC_E_LOGON_DENIED = HRESULT($8009030C);
  69. {$EXTERNALSYM SEC_E_LOGON_DENIED}
  70. SEC_E_UNKNOWN_CREDENTIALS = HRESULT($8009030D);
  71. {$EXTERNALSYM SEC_E_UNKNOWN_CREDENTIALS}
  72. SEC_E_NO_CREDENTIALS = HRESULT($8009030E);
  73. {$EXTERNALSYM SEC_E_NO_CREDENTIALS}
  74. SEC_E_MESSAGE_ALTERED = HRESULT($8009030F);
  75. {$EXTERNALSYM SEC_E_MESSAGE_ALTERED}
  76. SEC_E_OUT_OF_SEQUENCE = HRESULT($80090310);
  77. {$EXTERNALSYM SEC_E_OUT_OF_SEQUENCE}
  78. SEC_E_NO_AUTHENTICATING_AUTHORITY = HRESULT($80090311);
  79. {$EXTERNALSYM SEC_E_NO_AUTHENTICATING_AUTHORITY}
  80. SEC_I_CONTINUE_NEEDED = HRESULT($00090312);
  81. {$EXTERNALSYM SEC_I_CONTINUE_NEEDED}
  82. SEC_I_COMPLETE_NEEDED = HRESULT($00090313);
  83. {$EXTERNALSYM SEC_I_COMPLETE_NEEDED}
  84. SEC_I_COMPLETE_AND_CONTINUE = HRESULT($00090314);
  85. {$EXTERNALSYM SEC_I_COMPLETE_AND_CONTINUE}
  86. SEC_I_LOCAL_LOGON = HRESULT($00090315);
  87. {$EXTERNALSYM SEC_I_LOCAL_LOGON}
  88. SEC_E_BAD_PKGID = HRESULT($80090316);
  89. {$EXTERNALSYM SEC_E_BAD_PKGID}
  90. SEC_E_CONTEXT_EXPIRED = HRESULT($80090317);
  91. {$EXTERNALSYM SEC_E_CONTEXT_EXPIRED}
  92. SEC_E_INCOMPLETE_MESSAGE = HRESULT($80090318);
  93. {$EXTERNALSYM SEC_E_INCOMPLETE_MESSAGE}
  94. SEC_E_INCOMPLETE_CREDENTIALS = HRESULT($80090320);
  95. {$EXTERNALSYM SEC_E_INCOMPLETE_CREDENTIALS}
  96. SEC_E_BUFFER_TOO_SMALL = HRESULT($80090321);
  97. {$EXTERNALSYM SEC_E_BUFFER_TOO_SMALL}
  98. SEC_I_INCOMPLETE_CREDENTIALS = HRESULT($00090320);
  99. {$EXTERNALSYM SEC_I_INCOMPLETE_CREDENTIALS}
  100. SEC_I_RENEGOTIATE = HRESULT($00090321);
  101. {$EXTERNALSYM SEC_I_RENEGOTIATE}
  102. SEC_E_WRONG_PRINCIPAL = HRESULT($80090322);
  103. {$EXTERNALSYM SEC_E_WRONG_PRINCIPAL}
  104. SEC_I_NO_LSA_CONTEXT = HRESULT($00090323);
  105. {$EXTERNALSYM SEC_I_NO_LSA_CONTEXT}
  106. SEC_E_TIME_SKEW = HRESULT($80090324);
  107. {$EXTERNALSYM SEC_E_TIME_SKEW}
  108. SEC_E_UNTRUSTED_ROOT = HRESULT($80090325);
  109. {$EXTERNALSYM SEC_E_UNTRUSTED_ROOT}
  110. SEC_E_ILLEGAL_MESSAGE = HRESULT($80090326);
  111. {$EXTERNALSYM SEC_E_ILLEGAL_MESSAGE}
  112. SEC_E_CERT_UNKNOWN = HRESULT($80090327);
  113. {$EXTERNALSYM SEC_E_CERT_UNKNOWN}
  114. SEC_E_CERT_EXPIRED = HRESULT($80090328);
  115. {$EXTERNALSYM SEC_E_CERT_EXPIRED}
  116. SEC_E_ENCRYPT_FAILURE = HRESULT($80090329);
  117. {$EXTERNALSYM SEC_E_ENCRYPT_FAILURE}
  118. SEC_E_DECRYPT_FAILURE = HRESULT($80090330);
  119. {$EXTERNALSYM SEC_E_DECRYPT_FAILURE}
  120. SEC_E_ALGORITHM_MISMATCH = HRESULT($80090331);
  121. {$EXTERNALSYM SEC_E_ALGORITHM_MISMATCH}
  122. SEC_E_SECURITY_QOS_FAILED = HRESULT($80090332);
  123. {$EXTERNALSYM SEC_E_SECURITY_QOS_FAILED}
  124. SEC_E_UNFINISHED_CONTEXT_DELETED = HRESULT($80090333);
  125. {$EXTERNALSYM SEC_E_UNFINISHED_CONTEXT_DELETED}
  126. SEC_E_NO_TGT_REPLY = HRESULT($80090334);
  127. {$EXTERNALSYM SEC_E_NO_TGT_REPLY}
  128. SEC_E_NO_IP_ADDRESSES = HRESULT($80090335);
  129. {$EXTERNALSYM SEC_E_NO_IP_ADDRESSES}
  130. SEC_E_WRONG_CREDENTIAL_HANDLE = HRESULT($80090336);
  131. {$EXTERNALSYM SEC_E_WRONG_CREDENTIAL_HANDLE}
  132. SEC_E_CRYPTO_SYSTEM_INVALID = HRESULT($80090337);
  133. {$EXTERNALSYM SEC_E_CRYPTO_SYSTEM_INVALID}
  134. SEC_E_MAX_REFERRALS_EXCEEDED = HRESULT($80090338);
  135. {$EXTERNALSYM SEC_E_MAX_REFERRALS_EXCEEDED}
  136. SEC_E_MUST_BE_KDC = HRESULT($80090339);
  137. {$EXTERNALSYM SEC_E_MUST_BE_KDC}
  138. SEC_E_STRONG_CRYPTO_NOT_SUPPORTED = HRESULT($8009033A);
  139. {$EXTERNALSYM SEC_E_STRONG_CRYPTO_NOT_SUPPORTED}
  140. SEC_E_TOO_MANY_PRINCIPALS = HRESULT($8009033B);
  141. {$EXTERNALSYM SEC_E_TOO_MANY_PRINCIPALS}
  142. SEC_E_NO_PA_DATA = HRESULT($8009033C);
  143. {$EXTERNALSYM SEC_E_NO_PA_DATA}
  144. SEC_E_PKINIT_NAME_MISMATCH = HRESULT($8009033D);
  145. {$EXTERNALSYM SEC_E_PKINIT_NAME_MISMATCH}
  146. SEC_E_SMARTCARD_LOGON_REQUIRED = HRESULT($8009033E);
  147. {$EXTERNALSYM SEC_E_SMARTCARD_LOGON_REQUIRED}
  148. SEC_E_SHUTDOWN_IN_PROGRESS = HRESULT($8009033F);
  149. {$EXTERNALSYM SEC_E_SHUTDOWN_IN_PROGRESS}
  150. SEC_E_KDC_INVALID_REQUEST = HRESULT($80090340);
  151. {$EXTERNALSYM SEC_E_KDC_INVALID_REQUEST}
  152. SEC_E_KDC_UNABLE_TO_REFER = HRESULT($80090341);
  153. {$EXTERNALSYM SEC_E_KDC_UNABLE_TO_REFER}
  154. SEC_E_KDC_UNKNOWN_ETYPE = HRESULT($80090342);
  155. {$EXTERNALSYM SEC_E_KDC_UNKNOWN_ETYPE}
  156. SEC_E_UNSUPPORTED_PREAUTH = HRESULT($80090343);
  157. {$EXTERNALSYM SEC_E_UNSUPPORTED_PREAUTH}
  158. SEC_E_DELEGATION_REQUIRED = HRESULT($80090345);
  159. {$EXTERNALSYM SEC_E_DELEGATION_REQUIRED}
  160. SEC_E_BAD_BINDINGS = HRESULT($80090346);
  161. {$EXTERNALSYM SEC_E_BAD_BINDINGS}
  162. SEC_E_MULTIPLE_ACCOUNTS = HRESULT($80090347);
  163. {$EXTERNALSYM SEC_E_MULTIPLE_ACCOUNTS}
  164. SEC_E_NO_KERB_KEY = HRESULT($80090348);
  165. {$EXTERNALSYM SEC_E_NO_KERB_KEY}
  166. SEC_E_CERT_WRONG_USAGE = HRESULT($80090349);
  167. {$EXTERNALSYM SEC_E_CERT_WRONG_USAGE}
  168. SEC_E_DOWNGRADE_DETECTED = HRESULT($80090350);
  169. {$EXTERNALSYM SEC_E_DOWNGRADE_DETECTED}
  170. SEC_E_SMARTCARD_CERT_REVOKED = HRESULT($80090351);
  171. {$EXTERNALSYM SEC_E_SMARTCARD_CERT_REVOKED}
  172. SEC_E_ISSUING_CA_UNTRUSTED = HRESULT($80090352);
  173. {$EXTERNALSYM SEC_E_ISSUING_CA_UNTRUSTED}
  174. SEC_E_REVOCATION_OFFLINE_C = HRESULT($80090353);
  175. {$EXTERNALSYM SEC_E_REVOCATION_OFFLINE_C}
  176. SEC_E_PKINIT_CLIENT_FAILURE = HRESULT($80090354);
  177. {$EXTERNALSYM SEC_E_PKINIT_CLIENT_FAILURE}
  178. SEC_E_SMARTCARD_CERT_EXPIRED = HRESULT($80090355);
  179. {$EXTERNALSYM SEC_E_SMARTCARD_CERT_EXPIRED}
  180. SEC_E_NO_S4U_PROT_SUPPORT = HRESULT($80090356);
  181. {$EXTERNALSYM SEC_E_NO_S4U_PROT_SUPPORT}
  182. SEC_E_CROSSREALM_DELEGATION_FAILURE = HRESULT($80090357);
  183. {$EXTERNALSYM SEC_E_CROSSREALM_DELEGATION_FAILURE}
  184. SEC_E_REVOCATION_OFFLINE_KDC = HRESULT($80090358);
  185. {$EXTERNALSYM SEC_E_REVOCATION_OFFLINE_KDC}
  186. SEC_E_ISSUING_CA_UNTRUSTED_KDC = HRESULT($80090359);
  187. {$EXTERNALSYM SEC_E_ISSUING_CA_UNTRUSTED_KDC}
  188. SEC_E_KDC_CERT_EXPIRED = HRESULT($8009035A);
  189. {$EXTERNALSYM SEC_E_KDC_CERT_EXPIRED}
  190. SEC_E_KDC_CERT_REVOKED = HRESULT($8009035B);
  191. {$EXTERNALSYM SEC_E_KDC_CERT_REVOKED}
  192. SEC_I_SIGNATURE_NEEDED = HRESULT($0009035C);
  193. {$EXTERNALSYM SEC_I_SIGNATURE_NEEDED}
  194. SEC_E_INVALID_PARAMETER = HRESULT($8009035D);
  195. {$EXTERNALSYM SEC_E_INVALID_PARAMETER}
  196. SEC_E_DELEGATION_POLICY = HRESULT($8009035E);
  197. {$EXTERNALSYM SEC_E_DELEGATION_POLICY}
  198. SEC_E_POLICY_NLTM_ONLY = HRESULT($8009035F);
  199. {$EXTERNALSYM SEC_E_POLICY_NLTM_ONLY}
  200. SEC_I_NO_RENEGOTIATION = HRESULT($00090360);
  201. {$EXTERNALSYM SEC_I_NO_RENEGOTIATION}
  202. SEC_E_NO_CONTEXT = HRESULT($80090361);
  203. {$EXTERNALSYM SEC_E_NO_CONTEXT}
  204. SEC_E_PKU2U_CERT_FAILURE = HRESULT($80090362);
  205. {$EXTERNALSYM SEC_E_PKU2U_CERT_FAILURE}
  206. SEC_E_MUTUAL_AUTH_FAILED = HRESULT($80090363);
  207. {$EXTERNALSYM SEC_E_MUTUAL_AUTH_FAILED}
  208. type
  209. ESSPIException = class(Exception)
  210. public
  211. // Params must be in this order to avoid conflict with CreateHelp
  212. // constructor in CBuilder as CB does not differentiate constructors
  213. // by name as Delphi does
  214. constructor CreateError(const AErrorNo: Integer; const AFailedFuncName: string);
  215. //
  216. class function GetErrorMessageByNo(AErrorNo: UInt32): string;
  217. end;
  218. ESSPIInterfaceInitFailed = class(ESSPIException);
  219. { TSSPIInterface }
  220. TSSPIInterface = class(TObject)
  221. private
  222. fLoadPending, fIsAvailable: Boolean;
  223. fPFunctionTable: PSecurityFunctionTable;
  224. fDLLHandle: TIdLibHandle;
  225. procedure ReleaseFunctionTable;
  226. procedure CheckAvailable;
  227. function GetFunctionTable: SecurityFunctionTable;
  228. public
  229. class procedure RaiseIfError(aStatus: SECURITY_STATUS; const aFunctionName: string);
  230. function IsAvailable: Boolean;
  231. property FunctionTable: SecurityFunctionTable read GetFunctionTable;
  232. public
  233. constructor Create;
  234. destructor Destroy; override;
  235. end;
  236. { TSSPIPackages }
  237. TSSPIPackage = class(TObject)
  238. private
  239. fPSecPkginfo: PSecPkgInfo;
  240. function GetPSecPkgInfo: PSecPkgInfo;
  241. function GetMaxToken: ULONG;
  242. function GetName: {$IFDEF SSPI_UNICODE}TIdUnicodeString{$ELSE}AnsiString{$ENDIF};
  243. public
  244. property MaxToken: ULONG read GetMaxToken;
  245. property Name: {$IFDEF SSPI_UNICODE}TIdUnicodeString{$ELSE}AnsiString{$ENDIF} read GetName;
  246. public
  247. constructor Create(aPSecPkginfo: PSecPkgInfo);
  248. end;
  249. TCustomSSPIPackage = class(TSSPIPackage)
  250. private
  251. fInfo: PSecPkgInfo;
  252. public
  253. constructor Create(const aPkgName: {$IFDEF SSPI_UNICODE}TIdUnicodeString{$ELSE}AnsiString{$ENDIF});
  254. destructor Destroy; override;
  255. end;
  256. TSSPINTLMPackage = class(TCustomSSPIPackage)
  257. public
  258. constructor Create;
  259. end;
  260. { TSSPICredentials }
  261. TSSPICredentialsUse = (scuInBound, scuOutBound, scuBoth);
  262. TSSPICredentials = class(TObject)
  263. private
  264. fPackage: TSSPIPackage;
  265. fHandle: CredHandle;
  266. fUse: TSSPICredentialsUse;
  267. fAcquired: Boolean;
  268. fExpiry: TimeStamp;
  269. function GetHandle: PCredHandle;
  270. procedure SetUse(aValue: TSSPICredentialsUse);
  271. protected
  272. procedure CheckAcquired;
  273. procedure CheckNotAcquired;
  274. procedure DoAcquire(pszPrincipal: {$IFDEF SSPI_UNICODE}PSEC_WCHAR{$ELSE}PSEC_CHAR{$ENDIF}; pvLogonId, pAuthData: PVOID);
  275. procedure DoRelease; virtual;
  276. public
  277. procedure Release;
  278. property Package: TSSPIPackage read fPackage;
  279. property Handle: PCredHandle read GetHandle;
  280. property Use: TSSPICredentialsUse read fUse write SetUse;
  281. property Acquired: Boolean read fAcquired;
  282. public
  283. constructor Create(aPackage: TSSPIPackage);
  284. destructor Destroy; override;
  285. end;
  286. { TSSPIWinNTCredentials }
  287. TSSPIWinNTCredentials = class(TSSPICredentials)
  288. protected
  289. public
  290. procedure Acquire(aUse: TSSPICredentialsUse); overload;
  291. procedure Acquire(aUse: TSSPICredentialsUse;
  292. const aDomain, aUserName, aPassword: {$IFDEF SSPI_UNICODE}TIdUnicodeString{$ELSE}AnsiString{$ENDIF}); overload;
  293. end;
  294. { TSSPIContext }
  295. TSSPIContext = class(TObject)
  296. private
  297. fCredentials: TSSPICredentials;
  298. fHandle: CtxtHandle;
  299. fHasHandle: Boolean;
  300. fExpiry: TimeStamp;
  301. function GetHandle: PCtxtHandle;
  302. function GetExpiry: TimeStamp;
  303. procedure UpdateHasContextAndCheckForError(
  304. const aFuncResult: SECURITY_STATUS; const aFuncName: string;
  305. const aErrorsToIgnore: array of SECURITY_STATUS);
  306. protected
  307. procedure CheckHasHandle;
  308. procedure CheckCredentials;
  309. function DoInitialize(const aTokenSourceName: {$IFDEF SSPI_UNICODE}TIdUnicodeString{$ELSE}AnsiString{$ENDIF};
  310. var aIn, aOut: SecBufferDesc;
  311. const errorsToIgnore: array of SECURITY_STATUS): SECURITY_STATUS;
  312. procedure DoRelease; virtual;
  313. function GetRequestedFlags: ULONG; virtual; abstract;
  314. procedure SetEstablishedFlags(aFlags: ULONG); virtual; abstract;
  315. function GetAuthenticated: Boolean; virtual; abstract;
  316. property HasHandle: Boolean read fHasHandle;
  317. public
  318. procedure Release;
  319. property Credentials: TSSPICredentials read fCredentials;
  320. property Handle: PCtxtHandle read GetHandle;
  321. property Authenticated: Boolean read GetAuthenticated;
  322. property Expiry: TimeStamp read GetExpiry;
  323. public
  324. constructor Create(aCredentials: TSSPICredentials);
  325. destructor Destroy; override;
  326. end;
  327. { TSSPIConnectionContext }
  328. TCustomSSPIConnectionContext = class(TSSPIContext)
  329. private
  330. fStatus: SECURITY_STATUS;
  331. fOutBuffDesc, fInBuffDesc: SecBufferDesc;
  332. fInBuff: SecBuffer;
  333. protected
  334. procedure DoRelease; override;
  335. function GetAuthenticated: Boolean; override;
  336. function DoUpdateAndGenerateReply(var aIn, aOut: SecBufferDesc;
  337. const aErrorsToIgnore: array of SECURITY_STATUS
  338. ): SECURITY_STATUS; virtual; abstract;
  339. public
  340. constructor Create(ACredentials: TSSPICredentials);
  341. function UpdateAndGenerateReply(
  342. const aFromPeerToken: TIdBytes; var aToPeerToken: TIdBytes): Boolean;
  343. end;
  344. TSSPIClientConnectionContext = class(TCustomSSPIConnectionContext)
  345. private
  346. fTargetName: string;
  347. fReqReguested, fReqEstablished: ULONG;
  348. protected
  349. function GetRequestedFlags: ULONG; override;
  350. procedure SetEstablishedFlags(aFlags: ULONG); override;
  351. function DoUpdateAndGenerateReply(var aIn, aOut: SecBufferDesc;
  352. const aErrorsToIgnore: array of SECURITY_STATUS
  353. ): SECURITY_STATUS; override;
  354. public
  355. function GenerateInitialChallenge(const aTargetName: string;
  356. var aToPeerToken: TIdBytes): Boolean;
  357. public
  358. constructor Create(aCredentials: TSSPICredentials);
  359. end;
  360. TIndySSPINTLMClient = class(TObject)
  361. protected
  362. fNTLMPackage: TSSPINTLMPackage;
  363. fCredentials: TSSPIWinNTCredentials;
  364. fContext: TSSPIClientConnectionContext;
  365. public
  366. procedure SetCredentials(const aDomain, aUserName, aPassword: string);
  367. procedure SetCredentialsAsCurrentUser;
  368. function InitAndBuildType1Message: TIdBytes;
  369. function UpdateAndBuildType3Message(const aServerType2Message: TIdBytes): TIdBytes;
  370. public
  371. constructor Create;
  372. destructor Destroy; override;
  373. end;
  374. TIdSSPINTLMAuthentication = class(TIdAuthentication)
  375. protected
  376. FNTLMInfo: string;
  377. FSSPIClient: TIndySSPINTLMClient;
  378. procedure SetDomain(const Value: String);
  379. function GetDomain: String;
  380. procedure SetUserName(const Value: String); override;
  381. function GetSteps: Integer; override;
  382. function DoNext: TIdAuthWhatsNext; override;
  383. public
  384. constructor Create; override;
  385. destructor Destroy; override;
  386. function Authentication: string; override;
  387. function KeepAlive: Boolean; override;
  388. property Domain: String read GetDomain write SetDomain;
  389. end;
  390. // RLebeau 4/17/10: this forces C++Builder to link to this unit so
  391. // RegisterAuthenticationMethod can be called correctly at program startup...
  392. {$IFDEF HAS_DIRECTIVE_HPPEMIT_LINKUNIT}
  393. {$HPPEMIT LINKUNIT}
  394. {$ELSE}
  395. {$HPPEMIT '#pragma link "IdAuthenticationSSPI"'}
  396. {$ENDIF}
  397. implementation
  398. uses
  399. IdGlobalProtocols,
  400. IdCoderMIME,
  401. IdResourceStringsSSPI,
  402. IdHeaderList;
  403. var
  404. gSSPIInterface: TSSPIInterface = nil;
  405. gAuthRegistered: Boolean = False;
  406. { ESSPIException }
  407. class function ESSPIException.GetErrorMessageByNo(aErrorNo: UInt32): string;
  408. begin
  409. case HRESULT(aErrorNo) of
  410. SEC_E_OK:
  411. Result := RSHTTPSSPISuccess;
  412. SEC_E_INSUFFICIENT_MEMORY:
  413. Result := RSHTTPSSPINotEnoughMem;
  414. SEC_E_INVALID_HANDLE:
  415. Result := RSHTTPSSPIInvalidHandle;
  416. SEC_E_UNSUPPORTED_FUNCTION:
  417. Result := RSHTTPSSPIFuncNotSupported;
  418. SEC_E_TARGET_UNKNOWN:
  419. Result := RSHTTPSSPIUnknownTarget;
  420. SEC_E_INTERNAL_ERROR:
  421. Result := RSHTTPSSPIInternalError;
  422. SEC_E_SECPKG_NOT_FOUND:
  423. Result := RSHTTPSSPISecPackageNotFound;
  424. SEC_E_NOT_OWNER:
  425. Result := RSHTTPSSPINotOwner;
  426. SEC_E_CANNOT_INSTALL:
  427. Result := RSHTTPSSPIPackageCannotBeInstalled;
  428. SEC_E_INVALID_TOKEN:
  429. Result := RSHTTPSSPIInvalidToken;
  430. SEC_E_CANNOT_PACK:
  431. Result := RSHTTPSSPICannotPack;
  432. SEC_E_QOP_NOT_SUPPORTED:
  433. Result := RSHTTPSSPIQOPNotSupported;
  434. SEC_E_NO_IMPERSONATION:
  435. Result := RSHTTPSSPINoImpersonation;
  436. SEC_E_LOGON_DENIED:
  437. Result := RSHTTPSSPILoginDenied;
  438. SEC_E_UNKNOWN_CREDENTIALS:
  439. Result := RSHTTPSSPIUnknownCredentials;
  440. SEC_E_NO_CREDENTIALS:
  441. Result := RSHTTPSSPINoCredentials;
  442. SEC_E_MESSAGE_ALTERED:
  443. Result := RSHTTPSSPIMessageAltered;
  444. SEC_E_OUT_OF_SEQUENCE:
  445. Result := RSHTTPSSPIOutOfSequence;
  446. SEC_E_NO_AUTHENTICATING_AUTHORITY:
  447. Result := RSHTTPSSPINoAuthAuthority;
  448. SEC_I_CONTINUE_NEEDED:
  449. Result := RSHTTPSSPIContinueNeeded;
  450. SEC_I_COMPLETE_NEEDED:
  451. Result := RSHTTPSSPICompleteNeeded;
  452. SEC_I_COMPLETE_AND_CONTINUE:
  453. Result :=RSHTTPSSPICompleteContinueNeeded;
  454. SEC_I_LOCAL_LOGON:
  455. Result := RSHTTPSSPILocalLogin;
  456. SEC_E_BAD_PKGID:
  457. Result := RSHTTPSSPIBadPackageID;
  458. SEC_E_CONTEXT_EXPIRED:
  459. Result := RSHTTPSSPIContextExpired;
  460. SEC_E_INCOMPLETE_MESSAGE:
  461. Result := RSHTTPSSPIIncompleteMessage;
  462. SEC_E_INCOMPLETE_CREDENTIALS:
  463. Result := RSHTTPSSPIIncompleteCredentialNotInit;
  464. SEC_E_BUFFER_TOO_SMALL:
  465. Result := RSHTTPSSPIBufferTooSmall;
  466. SEC_I_INCOMPLETE_CREDENTIALS:
  467. Result := RSHTTPSSPIIncompleteCredentialsInit;
  468. SEC_I_RENEGOTIATE:
  469. Result := RSHTTPSSPIRengotiate;
  470. SEC_E_WRONG_PRINCIPAL:
  471. Result := RSHTTPSSPIWrongPrincipal;
  472. SEC_I_NO_LSA_CONTEXT:
  473. Result := RSHTTPSSPINoLSACode;
  474. SEC_E_TIME_SKEW:
  475. Result := RSHTTPSSPITimeScew;
  476. SEC_E_UNTRUSTED_ROOT:
  477. Result := RSHTTPSSPIUntrustedRoot;
  478. SEC_E_ILLEGAL_MESSAGE:
  479. Result := RSHTTPSSPIIllegalMessage;
  480. SEC_E_CERT_UNKNOWN:
  481. Result := RSHTTPSSPICertUnknown;
  482. SEC_E_CERT_EXPIRED:
  483. Result := RSHTTPSSPICertExpired;
  484. SEC_E_ENCRYPT_FAILURE:
  485. Result := RSHTTPSSPIEncryptionFailure;
  486. SEC_E_DECRYPT_FAILURE:
  487. Result := RSHTTPSSPIDecryptionFailure;
  488. SEC_E_ALGORITHM_MISMATCH:
  489. Result := RSHTTPSSPIAlgorithmMismatch;
  490. SEC_E_SECURITY_QOS_FAILED:
  491. Result := RSHTTPSSPISecurityQOSFailure;
  492. SEC_E_UNFINISHED_CONTEXT_DELETED :
  493. Result := RSHTTPSSPISecCtxWasDelBeforeUpdated;
  494. SEC_E_NO_TGT_REPLY :
  495. Result := RSHTTPSSPIClientNoTGTReply;
  496. SEC_E_NO_IP_ADDRESSES :
  497. Result := RSHTTPSSPILocalNoIPAddr;
  498. SEC_E_WRONG_CREDENTIAL_HANDLE :
  499. Result := RSHTTPSSPIWrongCredHandle;
  500. SEC_E_CRYPTO_SYSTEM_INVALID :
  501. Result := RSHTTPSSPICryptoSysInvalid;
  502. SEC_E_MAX_REFERRALS_EXCEEDED :
  503. Result := RSHTTPSSPIMaxTicketRef;
  504. SEC_E_MUST_BE_KDC :
  505. Result := RSHTTPSSPIMustBeKDC;
  506. SEC_E_STRONG_CRYPTO_NOT_SUPPORTED :
  507. Result := RSHTTPSSPIStrongCryptoNotSupported;
  508. SEC_E_TOO_MANY_PRINCIPALS :
  509. Result := RSHTTPSSPIKDCReplyTooManyPrincipals;
  510. SEC_E_NO_PA_DATA :
  511. Result := RSHTTPSSPINoPAData;
  512. SEC_E_PKINIT_NAME_MISMATCH :
  513. Result := RSHTTPSSPIPKInitNameMismatch;
  514. SEC_E_SMARTCARD_LOGON_REQUIRED :
  515. Result := RSHTTPSSPISmartcardLogonReq;
  516. SEC_E_SHUTDOWN_IN_PROGRESS :
  517. Result := RSHTTPSSPISysShutdownInProg;
  518. SEC_E_KDC_INVALID_REQUEST :
  519. Result := RSHTTPSSPIKDCInvalidRequest;
  520. SEC_E_KDC_UNABLE_TO_REFER :
  521. Result := RSHTTPSSPIKDCUnableToRefer;
  522. SEC_E_KDC_UNKNOWN_ETYPE :
  523. Result := RSHTTPSSPIKDCETypeUnknown;
  524. SEC_E_UNSUPPORTED_PREAUTH :
  525. Result := RSHTTPSSPIUnsupPreauth;
  526. SEC_E_DELEGATION_REQUIRED :
  527. Result := RSHTTPSSPIDeligationReq;
  528. SEC_E_BAD_BINDINGS :
  529. Result := RSHTTPSSPIBadBindings;
  530. SEC_E_MULTIPLE_ACCOUNTS :
  531. Result := RSHTTPSSPIMultipleAccounts;
  532. SEC_E_NO_KERB_KEY :
  533. Result := RSHTTPSSPINoKerbKey;
  534. SEC_E_CERT_WRONG_USAGE :
  535. Result := RSHTTPSSPICertWrongUsage;
  536. SEC_E_DOWNGRADE_DETECTED :
  537. Result := RSHTTPSSPIDowngradeDetected;
  538. SEC_E_SMARTCARD_CERT_REVOKED :
  539. Result := RSHTTPSSPISmartcardCertRevoked;
  540. SEC_E_ISSUING_CA_UNTRUSTED :
  541. Result := RSHTTPSSPIIssuingCAUntrusted;
  542. SEC_E_REVOCATION_OFFLINE_C :
  543. Result := RSHTTPSSPIRevocationOffline;
  544. SEC_E_PKINIT_CLIENT_FAILURE :
  545. Result := RSHTTPSSPIPKInitClientFailure;
  546. SEC_E_SMARTCARD_CERT_EXPIRED :
  547. Result := RSHTTPSSPISmartcardExpired;
  548. SEC_E_NO_S4U_PROT_SUPPORT :
  549. Result := RSHTTPSSPINoS4UProtSupport;
  550. SEC_E_CROSSREALM_DELEGATION_FAILURE :
  551. Result := RSHTTPSSPICrossRealmDeligationFailure;
  552. SEC_E_REVOCATION_OFFLINE_KDC :
  553. Result := RSHTTPSSPIRevocationOfflineKDC;
  554. SEC_E_ISSUING_CA_UNTRUSTED_KDC :
  555. Result := RSHTTPSSPICAUntrustedKDC;
  556. SEC_E_KDC_CERT_EXPIRED :
  557. Result := RSHTTPSSPIKDCCertExpired;
  558. SEC_E_KDC_CERT_REVOKED :
  559. Result := RSHTTPSSPIKDCCertRevoked;
  560. SEC_I_SIGNATURE_NEEDED :
  561. Result := RSHTTPSSPISignatureNeeded;
  562. SEC_E_INVALID_PARAMETER :
  563. Result := RSHTTPSSPIInvalidParameter;
  564. SEC_E_DELEGATION_POLICY :
  565. Result := RSHTTPSSPIDeligationPolicy;
  566. SEC_E_POLICY_NLTM_ONLY :
  567. Result := RSHTTPSSPIPolicyNTLMOnly;
  568. SEC_I_NO_RENEGOTIATION :
  569. Result := RSHTTPSSPINoRenegotiation;
  570. SEC_E_NO_CONTEXT :
  571. Result := RSHTTPSSPINoContext;
  572. SEC_E_PKU2U_CERT_FAILURE :
  573. Result := RSHTTPSSPIPKU2UCertFailure;
  574. SEC_E_MUTUAL_AUTH_FAILED :
  575. Result := RSHTTPSSPIMutualAuthFailed;
  576. else
  577. Result := RSHTTPSSPIUnknwonError;
  578. end;
  579. end;
  580. constructor ESSPIException.CreateError(const AErrorNo: Integer; const AFailedFuncName: string);
  581. begin
  582. if AErrorNo = SEC_E_OK then begin
  583. inherited Create(AFailedFuncName);
  584. end else begin
  585. inherited CreateFmt(RSHTTPSSPIErrorMsg,
  586. [AFailedFuncName, AErrorNo, AErrorNo, GetErrorMessageByNo(AErrorNo)]);
  587. end;
  588. end;
  589. { TSSPIInterface }
  590. procedure TSSPIInterface.ReleaseFunctionTable;
  591. begin
  592. if fPFunctionTable <> nil then begin
  593. fPFunctionTable := nil;
  594. end;
  595. end;
  596. procedure TSSPIInterface.CheckAvailable;
  597. begin
  598. if not IsAvailable then begin
  599. raise ESSPIInterfaceInitFailed.Create(RSHTTPSSPIInterfaceInitFailed);
  600. end;
  601. end;
  602. function TSSPIInterface.GetFunctionTable: SecurityFunctionTable;
  603. begin
  604. CheckAvailable;
  605. Result := fPFunctionTable^;
  606. end;
  607. class procedure TSSPIInterface.RaiseIfError(aStatus: SECURITY_STATUS;
  608. const aFunctionName: string);
  609. begin
  610. if not SEC_SUCCESS(aStatus) then begin
  611. raise ESSPIException.CreateError(aStatus, aFunctionName);
  612. end;
  613. end;
  614. function TSSPIInterface.IsAvailable: Boolean;
  615. procedure LoadDLL;
  616. const
  617. SECURITY_DLL_NT = 'security.dll'; {Do not translate}
  618. SECURITY_DLL_95 = 'secur32.dll'; {Do not translate}
  619. ENCRYPT_MESSAGE = 'EncryptMessage'; {Do not translate}
  620. DECRYPT_MESSAGE = 'DecryptMessage'; {Do not translate}
  621. var
  622. dllName: string;
  623. entrypoint: INIT_SECURITY_INTERFACE;
  624. begin
  625. fIsAvailable := False;
  626. if IndyWindowsPlatform = VER_PLATFORM_WIN32_WINDOWS then
  627. { Windows95 SSPI dll }
  628. dllName := SECURITY_DLL_95
  629. else
  630. { WindowsNT & Windows2000 SSPI dll }
  631. dllName := SECURITY_DLL_NT;
  632. { load SSPI dll }
  633. //In Windows, you should use SafeLoadLibrary instead of the LoadLibrary API
  634. //call because LoadLibrary messes with the FPU control word.
  635. fDLLHandle := SafeLoadLibrary(dllName);
  636. if fDLLHandle <> IdNilHandle then begin
  637. { get InitSecurityInterface entry point
  638. and call it to fetch SPPI function table}
  639. entrypoint := LoadLibFunction(fDLLHandle, SECURITY_ENTRYPOINT);
  640. fPFunctionTable := entrypoint();
  641. { let's see what SSPI functions are available
  642. and if we can continue on with the set }
  643. fIsAvailable :=
  644. Assigned({$IFDEF SSPI_UNICODE}fPFunctionTable^.QuerySecurityPackageInfoW{$ELSE}fPFunctionTable^.QuerySecurityPackageInfoA{$ENDIF}) and
  645. Assigned(fPFunctionTable^.FreeContextBuffer) and
  646. Assigned(fPFunctionTable^.DeleteSecurityContext) and
  647. Assigned(fPFunctionTable^.FreeCredentialsHandle) and
  648. Assigned({$IFDEF SSPI_UNICODE}fPFunctionTable^.AcquireCredentialsHandleW{$ELSE}fPFunctionTable^.AcquireCredentialsHandleA{$ENDIF}) and
  649. Assigned({$IFDEF SSPI_UNICODE}fPFunctionTable^.InitializeSecurityContextW{$ELSE}fPFunctionTable^.InitializeSecurityContextA{$ENDIF}) and
  650. Assigned(fPFunctionTable^.AcceptSecurityContext) and
  651. Assigned(fPFunctionTable^.ImpersonateSecurityContext) and
  652. Assigned(fPFunctionTable^.RevertSecurityContext) and
  653. Assigned({$IFDEF SSPI_UNICODE}fPFunctionTable^.QueryContextAttributesW{$ELSE}fPFunctionTable^.QueryContextAttributesA{$ENDIF}) and
  654. Assigned(fPFunctionTable^.MakeSignature) and
  655. Assigned(fPFunctionTable^.VerifySignature);
  656. {$IFDEF SET_ENCRYPT_IN_FT_WITH_GETPROCADDRESS_FUDGE}
  657. { fudge for Encrypt/DecryptMessage }
  658. if not Assigned(fPFunctionTable^.EncryptMessage) then begin
  659. fPFunctionTable^.EncryptMessage := LoadLibFunction(fDLLHandle, ENCRYPT_MESSAGE);
  660. end;
  661. if not Assigned(fPFunctionTable^.DecryptMessage) then begin
  662. fPFunctionTable^.DecryptMessage := LoadLibFunction(fDLLHandle, DECRYPT_MESSAGE);
  663. end;
  664. {$ENDIF}
  665. end;
  666. end;
  667. begin
  668. if not fIsAvailable then begin
  669. if fLoadPending then begin
  670. ReleaseFunctionTable;
  671. LoadDLL;
  672. fLoadPending := False;
  673. end;
  674. end;
  675. Result := fIsAvailable;
  676. end;
  677. constructor TSSPIInterface.Create;
  678. begin
  679. inherited Create;
  680. fLoadPending := True;
  681. fIsAvailable := False;
  682. fPFunctionTable := nil;
  683. end;
  684. destructor TSSPIInterface.Destroy;
  685. begin
  686. ReleaseFunctionTable;
  687. if fDLLHandle <> IdNilHandle then begin
  688. FreeLibrary(fDLLHandle);
  689. fDLLHandle := IdNilHandle;
  690. end;
  691. inherited Destroy;
  692. end;
  693. { TSSPIPackage }
  694. constructor TSSPIPackage.Create(aPSecPkginfo: PSecPkgInfo);
  695. begin
  696. inherited Create;
  697. fPSecPkginfo := aPSecPkginfo;
  698. end;
  699. function TSSPIPackage.GetPSecPkgInfo: PSecPkgInfo;
  700. begin
  701. if not Assigned(fPSecPkginfo) then begin
  702. raise ESSPIException.Create(RSHTTPSSPINoPkgInfoSpecified);
  703. end;
  704. Result := fPSecPkginfo;
  705. end;
  706. function TSSPIPackage.GetMaxToken: ULONG;
  707. begin
  708. Result := GetPSecPkgInfo^.cbMaxToken;
  709. end;
  710. function TSSPIPackage.GetName: {$IFDEF SSPI_UNICODE}TIdUnicodeString{$ELSE}AnsiString{$ENDIF};
  711. begin
  712. Result := GetPSecPkgInfo^.Name;
  713. end;
  714. { TCustomSSPIPackage }
  715. constructor TCustomSSPIPackage.Create(const aPkgName: {$IFDEF SSPI_UNICODE}TIdUnicodeString{$ELSE}AnsiString{$ENDIF});
  716. begin
  717. gSSPIInterface.RaiseIfError(
  718. {$IFDEF SSPI_UNICODE}
  719. gSSPIInterface.FunctionTable.QuerySecurityPackageInfoW(PWideChar(aPkgName), @fInfo),
  720. 'QuerySecurityPackageInfoW' {Do not translate}
  721. {$ELSE}
  722. gSSPIInterface.FunctionTable.QuerySecurityPackageInfoA(PAnsiChar(aPkgName), @fInfo),
  723. 'QuerySecurityPackageInfoA' {Do not translate}
  724. {$ENDIF}
  725. );
  726. inherited Create(fInfo);
  727. end;
  728. destructor TCustomSSPIPackage.Destroy;
  729. begin
  730. if fInfo <> nil then begin
  731. gSSPIInterface.RaiseIfError(
  732. gSSPIInterface.FunctionTable.FreeContextBuffer(fInfo), 'FreeContextBuffer'); {Do not localize}
  733. end;
  734. inherited Destroy;
  735. end;
  736. { TSSPINTLMPackage }
  737. constructor TSSPINTLMPackage.Create;
  738. begin
  739. inherited Create(NTLMSP_NAME);
  740. end;
  741. { TSSPICredentials }
  742. constructor TSSPICredentials.Create(aPackage: TSSPIPackage);
  743. begin
  744. inherited Create;
  745. fPackage := aPackage;
  746. fUse := scuOutBound;
  747. fAcquired := False;
  748. end;
  749. procedure TSSPICredentials.CheckAcquired;
  750. begin
  751. if not fAcquired then begin
  752. raise ESSPIException.Create(RSHTTPSSPINoCredentialHandle);
  753. end;
  754. end;
  755. procedure TSSPICredentials.CheckNotAcquired;
  756. begin
  757. if fAcquired then begin
  758. raise ESSPIException.Create(RSHTTPSSPICanNotChangeCredentials);
  759. end;
  760. end;
  761. procedure TSSPICredentials.DoAcquire
  762. (pszPrincipal: {$IFDEF SSPI_UNICODE}PSEC_WCHAR{$ELSE}PSEC_CHAR{$ENDIF}; pvLogonId, pAuthData: PVOID);
  763. var
  764. cu: ULONG;
  765. begin
  766. Release;
  767. case Use of
  768. scuInBound:
  769. cu := SECPKG_CRED_INBOUND;
  770. scuOutBound:
  771. cu := SECPKG_CRED_OUTBOUND;
  772. scuBoth:
  773. cu := SECPKG_CRED_BOTH;
  774. else
  775. raise ESSPIException.Create(RSHTTPSSPIUnknwonCredentialUse);
  776. end;
  777. gSSPIInterface.RaiseIfError(
  778. gSSPIInterface.FunctionTable.{$IFDEF SSPI_UNICODE}AcquireCredentialsHandleW{$ELSE}AcquireCredentialsHandleA{$ENDIF}(
  779. pszPrincipal, {$IFDEF SSPI_UNICODE}PSEC_WCHAR{$ELSE}PSEC_CHAR{$ENDIF}(Package.Name), cu, pvLogonId, pAuthData, nil, nil,
  780. @fHandle, @fExpiry),
  781. {$IFDEF SSPI_UNICODE}
  782. 'AcquireCredentialsHandleW' {Do not translater}
  783. {$ELSE}
  784. 'AcquireCredentialsHandleA' {Do not translater}
  785. {$ENDIF}
  786. );
  787. fAcquired := True;
  788. end;
  789. procedure TSSPICredentials.DoRelease;
  790. begin
  791. gSSPIInterface.RaiseIfError(
  792. gSSPIInterface.FunctionTable.FreeCredentialsHandle(@fHandle),
  793. 'FreeCredentialsHandle'); {Do not translate}
  794. SecInvalidateHandle(fHandle);
  795. end;
  796. procedure TSSPICredentials.Release;
  797. begin
  798. if fAcquired then begin
  799. DoRelease;
  800. fAcquired := False;
  801. end;
  802. end;
  803. function TSSPICredentials.GetHandle: PCredHandle;
  804. begin
  805. CheckAcquired;
  806. Result := @fHandle;
  807. end;
  808. procedure TSSPICredentials.SetUse(aValue: TSSPICredentialsUse);
  809. begin
  810. if fUse <> aValue then begin
  811. CheckNotAcquired;
  812. fUse := aValue;
  813. end;
  814. end;
  815. destructor TSSPICredentials.Destroy;
  816. begin
  817. Release;
  818. inherited Destroy;
  819. end;
  820. { TSSPIWinNTCredentials }
  821. procedure TSSPIWinNTCredentials.Acquire(aUse: TSSPICredentialsUse);
  822. begin
  823. Acquire(aUse, '', '', ''); {Do not translate}
  824. end;
  825. procedure TSSPIWinNTCredentials.Acquire(aUse: TSSPICredentialsUse;
  826. const aDomain, aUserName, aPassword: {$IFDEF SSPI_UNICODE}TIdUnicodeString{$ELSE}AnsiString{$ENDIF});
  827. var
  828. ai: SEC_WINNT_AUTH_IDENTITY;
  829. pai: PVOID;
  830. begin
  831. Use := aUse;
  832. if (Length(aDomain) > 0) and (Length(aUserName) > 0) then begin
  833. {$IFDEF SSPI_UNICODE}
  834. ai.User := PUSHORT(PWideChar(aUserName));
  835. ai.UserLength := Length(aUserName);
  836. ai.Domain := PUSHORT(PWideChar(aDomain));
  837. ai.DomainLength := Length(aDomain);
  838. ai.Password := PUSHORT(PWideChar(aPassword));
  839. ai.PasswordLength := Length(aPassword);
  840. ai.Flags := SEC_WINNT_AUTH_IDENTITY_UNICODE;
  841. {$ELSE}
  842. ai.User := PUCHAR(PAnsiChar(aUserName));
  843. ai.UserLength := Length(aUserName);
  844. ai.Domain := PUCHAR(PAnsiChar(aDomain));
  845. ai.DomainLength := Length(aDomain);
  846. ai.Password := PUCHAR(PAnsiChar(aPassword));
  847. ai.PasswordLength := Length(aPassword);
  848. ai.Flags := SEC_WINNT_AUTH_IDENTITY_ANSI;
  849. {$ENDIF}
  850. pai := @ai;
  851. end else
  852. begin
  853. pai := nil;
  854. end;
  855. DoAcquire(nil, nil, pai);
  856. end;
  857. { TSSPIContext }
  858. constructor TSSPIContext.Create(aCredentials: TSSPICredentials);
  859. begin
  860. inherited Create;
  861. fCredentials := aCredentials;
  862. fHasHandle := False;
  863. end;
  864. destructor TSSPIContext.Destroy;
  865. begin
  866. Release;
  867. inherited Destroy;
  868. end;
  869. procedure TSSPIContext.UpdateHasContextAndCheckForError(
  870. const aFuncResult: SECURITY_STATUS; const aFuncName: string;
  871. const aErrorsToIgnore: array of SECURITY_STATUS);
  872. var
  873. doRaise: Boolean;
  874. i: Integer;
  875. begin
  876. doRaise := not SEC_SUCCESS(aFuncResult);
  877. if doRaise then begin
  878. for i := Low(aErrorsToIgnore) to High(aErrorsToIgnore) do begin
  879. if aFuncResult = aErrorsToIgnore[i] then begin
  880. doRaise := False;
  881. Break;
  882. end;
  883. end;
  884. end;
  885. if doRaise then begin
  886. raise ESSPIException.CreateError(aFuncResult, aFuncName);
  887. end;
  888. fHasHandle := True;
  889. end;
  890. function TSSPIContext.DoInitialize(const aTokenSourceName: {$IFDEF SSPI_UNICODE}TIdUnicodeString{$ELSE}AnsiString{$ENDIF};
  891. var aIn, aOut: SecBufferDesc;
  892. const errorsToIgnore: array of SECURITY_STATUS): SECURITY_STATUS;
  893. var
  894. tmp: PCtxtHandle;
  895. tmp2: PSecBufferDesc;
  896. r: ULONG;
  897. begin
  898. if fHasHandle then begin
  899. tmp := @fHandle;
  900. tmp2 := @aIn;
  901. end else begin
  902. tmp := nil;
  903. tmp2 := nil;
  904. end;
  905. Result :=
  906. gSSPIInterface.FunctionTable.{$IFDEF SSPI_UNICODE}InitializeSecurityContextW{$ELSE}InitializeSecurityContextA{$ENDIF}(
  907. Credentials.Handle, tmp,
  908. {$IFDEF SSPI_UNICODE}PWideChar{$ELSE}PAnsiChar{$ENDIF}(aTokenSourceName),
  909. GetRequestedFlags, 0, SECURITY_NATIVE_DREP, tmp2, 0,
  910. @fHandle, @aOut, @r, @fExpiry
  911. );
  912. UpdateHasContextAndCheckForError(Result,
  913. {$IFDEF SSPI_UNICODE}'InitializeSecurityContextW'{$ELSE}'InitializeSecurityContextA'{$ENDIF}, {Do not translate}
  914. errorsToIgnore);
  915. SetEstablishedFlags(r);
  916. end;
  917. procedure TSSPIContext.DoRelease;
  918. begin
  919. gSSPIInterface.RaiseIfError(
  920. gSSPIInterface.FunctionTable.DeleteSecurityContext(@fHandle), 'DeleteSecurityContext'); {Do not translate}
  921. end;
  922. procedure TSSPIContext.Release;
  923. begin
  924. if HasHandle then begin
  925. DoRelease;
  926. fHasHandle := False;
  927. end;
  928. end;
  929. procedure TSSPIContext.CheckHasHandle;
  930. begin
  931. if not HasHandle then begin
  932. raise ESSPIException.Create(RSHTTPSSPINoCredentialHandle);
  933. end;
  934. end;
  935. procedure TSSPIContext.CheckCredentials;
  936. begin
  937. if (not Assigned(Credentials)) or (not Credentials.Acquired) then begin
  938. raise ESSPIException.Create(RSHTTPSSPIDoAuquireCredentialHandle);
  939. end;
  940. end;
  941. function TSSPIContext.GetExpiry: TimeStamp;
  942. begin
  943. CheckHasHandle;
  944. Result := fExpiry;
  945. end;
  946. function TSSPIContext.GetHandle: PCtxtHandle;
  947. begin
  948. CheckHasHandle;
  949. Result := @fHandle;
  950. end;
  951. { TCustomSSPIConnectionContext }
  952. procedure TCustomSSPIConnectionContext.DoRelease;
  953. begin
  954. inherited DoRelease;
  955. fStatus := SEC_E_INVALID_HANDLE; // just to put something other then SEC_E_OK
  956. end;
  957. function TCustomSSPIConnectionContext.GetAuthenticated: Boolean;
  958. begin
  959. CheckHasHandle;
  960. Result := fStatus = SEC_E_OK;
  961. end;
  962. function TCustomSSPIConnectionContext.UpdateAndGenerateReply
  963. (const aFromPeerToken: TIdBytes; var aToPeerToken: TIdBytes): Boolean;
  964. var
  965. fOutBuff: SecBuffer;
  966. begin
  967. // keep the compiler happy (when was this fixed exactly?)
  968. {$IFDEF DCC}{$IFNDEF VCL_8_OR_ABOVE}
  969. Result := False;
  970. {$ENDIF}{$ENDIF}
  971. { check credentials }
  972. CheckCredentials;
  973. { prepare input buffer }
  974. fInBuff.cbBuffer := Length(aFromPeerToken);
  975. //Assert(Length(aFromPeerToken)>0);
  976. if fInBuff.cbBuffer > 0 then begin
  977. fInBuff.pvBuffer := @aFromPeerToken[0];
  978. end;
  979. { prepare output buffer }
  980. fOutBuff.BufferType := SECBUFFER_TOKEN;
  981. fOutBuff.cbBuffer := Credentials.Package.MaxToken;
  982. fOutBuff.pvBuffer := AllocMem(fOutBuff.cbBuffer);
  983. fOutBuffDesc.ulVersion := SECBUFFER_VERSION;
  984. fOutBuffDesc.cBuffers := 1;
  985. fOutBuffDesc.pBuffers := @fOutBuff;
  986. try
  987. { do processing }
  988. fStatus := DoUpdateAndGenerateReply(fInBuffDesc, fOutBuffDesc, []);
  989. { complete token if applicable }
  990. case fStatus of
  991. SEC_I_COMPLETE_NEEDED,
  992. SEC_I_COMPLETE_AND_CONTINUE:
  993. begin
  994. if not Assigned(gSSPIInterface.FunctionTable.CompleteAuthToken) then begin
  995. raise ESSPIException.Create(RSHTTPSSPICompleteTokenNotSupported);
  996. end;
  997. fStatus := gSSPIInterface.FunctionTable.CompleteAuthToken(Handle, @fOutBuffDesc);
  998. gSSPIInterface.RaiseIfError(fStatus, 'CompleteAuthToken'); {Do not translate}
  999. end;
  1000. end;
  1001. Result :=
  1002. (fStatus = SEC_I_CONTINUE_NEEDED) or
  1003. (fStatus = SEC_I_COMPLETE_AND_CONTINUE) or
  1004. (fOutBuff.cbBuffer > 0);
  1005. if Result then begin
  1006. aToPeerToken := RawToBytes(fOutBuff.pvBuffer^, fOutBuff.cbBuffer);
  1007. end;
  1008. finally
  1009. FreeMem(fOutBuff.pvBuffer);
  1010. end;
  1011. end;
  1012. constructor TCustomSSPIConnectionContext.Create(aCredentials: TSSPICredentials);
  1013. begin
  1014. inherited Create(aCredentials);
  1015. fInBuff.BufferType := SECBUFFER_TOKEN;
  1016. fInBuffDesc.ulVersion := SECBUFFER_VERSION;
  1017. fInBuffDesc.cBuffers := 1;
  1018. fInBuffDesc.pBuffers := @fInBuff;
  1019. fOutBuffDesc.ulVersion := SECBUFFER_VERSION;
  1020. fOutBuffDesc.cBuffers := 1;
  1021. end;
  1022. { TSSPIClientConnectionContext }
  1023. constructor TSSPIClientConnectionContext.Create(aCredentials: TSSPICredentials);
  1024. begin
  1025. inherited Create(aCredentials);
  1026. fTargetName := ''; {Do not translate}
  1027. end;
  1028. function TSSPIClientConnectionContext.GetRequestedFlags: ULONG;
  1029. begin
  1030. Result := fReqReguested;
  1031. end;
  1032. procedure TSSPIClientConnectionContext.SetEstablishedFlags(aFlags: ULONG);
  1033. begin
  1034. fReqEstablished := aFlags;
  1035. end;
  1036. function TSSPIClientConnectionContext.DoUpdateAndGenerateReply
  1037. (var aIn, aOut: SecBufferDesc;
  1038. const aErrorsToIgnore: array of SECURITY_STATUS): SECURITY_STATUS;
  1039. begin
  1040. Result := DoInitialize(fTargetName, aIn, aOut, []);
  1041. end;
  1042. function TSSPIClientConnectionContext.GenerateInitialChallenge
  1043. (const aTargetName: string; var aToPeerToken: TIdBytes): Boolean;
  1044. begin
  1045. Release;
  1046. fTargetName := aTargetName;
  1047. Result := UpdateAndGenerateReply(nil, aToPeerToken); {Do not translate}
  1048. end;
  1049. { TIndySSPINTLMClient }
  1050. constructor TIndySSPINTLMClient.Create;
  1051. begin
  1052. inherited Create;
  1053. fNTLMPackage := TSSPINTLMPackage.Create;
  1054. fCredentials := TSSPIWinNTCredentials.Create(fNTLMPackage);
  1055. fContext := TSSPIClientConnectionContext.Create(fCredentials);
  1056. end;
  1057. destructor TIndySSPINTLMClient.Destroy;
  1058. begin
  1059. FreeAndNil(fContext);
  1060. FreeAndNil(fCredentials);
  1061. FreeAndNil(fNTLMPackage);
  1062. inherited Destroy;
  1063. end;
  1064. procedure TIndySSPINTLMClient.SetCredentials(const aDomain, aUserName, aPassword: string);
  1065. begin
  1066. fCredentials.Acquire(scuOutBound, aDomain, aUserName, aPassword);
  1067. end;
  1068. procedure TIndySSPINTLMClient.SetCredentialsAsCurrentUser;
  1069. begin
  1070. fCredentials.Acquire(scuOutBound);
  1071. end;
  1072. function TIndySSPINTLMClient.InitAndBuildType1Message: TIdBytes;
  1073. begin
  1074. fContext.GenerateInitialChallenge('', Result);
  1075. end;
  1076. function TIndySSPINTLMClient.UpdateAndBuildType3Message(const aServerType2Message: TIdBytes): TIdBytes;
  1077. begin
  1078. fContext.UpdateAndGenerateReply(aServerType2Message, Result);
  1079. end;
  1080. { TIdSSPINTLMAuthentication }
  1081. constructor TIdSSPINTLMAuthentication.Create;
  1082. begin
  1083. inherited Create;
  1084. FSSPIClient := TIndySSPINTLMClient.Create;
  1085. Domain := IndyComputerName;
  1086. end;
  1087. function TIdSSPINTLMAuthentication.DoNext: TIdAuthWhatsNext;
  1088. begin
  1089. Result := wnDoRequest;
  1090. case FCurrentStep of
  1091. //Authentication() does the 2>3 progression
  1092. 0, 1, 3:
  1093. begin
  1094. Inc(FCurrentStep);
  1095. Result := wnDoRequest;
  1096. end;
  1097. 4:
  1098. begin
  1099. FCurrentStep := 0;
  1100. if Username = '' then begin
  1101. Result := wnAskTheProgram;
  1102. end else begin
  1103. Result := wnFail;
  1104. Username := '';
  1105. Password := '';
  1106. Domain := IndyComputerName;
  1107. end;
  1108. end;
  1109. end;
  1110. end;
  1111. function TIdSSPINTLMAuthentication.Authentication: string;
  1112. var
  1113. buf: TIdBytes;
  1114. begin
  1115. Result := '';
  1116. buf := nil;
  1117. case FCurrentStep of
  1118. 1:
  1119. begin
  1120. if Length(Username) = 0 then begin
  1121. FSSPIClient.SetCredentialsAsCurrentUser;
  1122. end else begin
  1123. FSSPIClient.SetCredentials(Domain, Username, Password);
  1124. end;
  1125. Result := 'NTLM ' + TIdEncoderMIME.EncodeBytes(FSSPIClient.InitAndBuildType1Message); {Do not translate}
  1126. FNTLMInfo := ''; {Do not translate}
  1127. end;
  1128. 2:
  1129. begin
  1130. if Length(FNTLMInfo) = 0 then begin
  1131. FNTLMInfo := ReadAuthInfo('NTLM'); {Do not translate}
  1132. Fetch(FNTLMInfo);
  1133. end;
  1134. if Length(FNTLMInfo) = 0 then begin
  1135. Reset;
  1136. Abort;
  1137. end;
  1138. buf := TIdDecoderMIME.DecodeBytes(FNTLMInfo);
  1139. Result := 'NTLM ' + TIdEncoderMIME.EncodeBytes(FSSPIClient.UpdateAndBuildType3Message(buf)); {Do not translate}
  1140. FCurrentStep := 3;
  1141. end;
  1142. 3: begin
  1143. FCurrentStep := 4;
  1144. end;
  1145. end;
  1146. end;
  1147. function TIdSSPINTLMAuthentication.KeepAlive: Boolean;
  1148. begin
  1149. Result := FCurrentStep >= 1;
  1150. end;
  1151. function TIdSSPINTLMAuthentication.GetSteps: Integer;
  1152. begin
  1153. Result := 3;
  1154. end;
  1155. procedure TIdSSPINTLMAuthentication.SetDomain(const Value: String);
  1156. begin
  1157. Params.Values['Domain'] := Value; {do not localize}
  1158. end;
  1159. function TIdSSPINTLMAuthentication.GetDomain: String;
  1160. begin
  1161. Result := Params.Values['Domain']; {do not localize}
  1162. end;
  1163. procedure TIdSSPINTLMAuthentication.SetUserName(const Value: String);
  1164. var
  1165. S: String;
  1166. Idx: Integer;
  1167. begin
  1168. S := Value;
  1169. Idx := IndyPos('\', S);
  1170. if Idx > 0 then begin
  1171. Domain := Copy(S, 1, Idx - 1);
  1172. Delete(S, 1, Idx);
  1173. end;
  1174. inherited SetUserName(S);
  1175. end;
  1176. destructor TIdSSPINTLMAuthentication.Destroy;
  1177. begin
  1178. FreeAndNil(FSSPIClient);
  1179. inherited;
  1180. end;
  1181. initialization
  1182. gSSPIInterface := TSSPIInterface.Create;
  1183. if gSSPIInterface.IsAvailable then begin
  1184. RegisterAuthenticationMethod('NTLM', TIdSSPINTLMAuthentication); {do not localize}
  1185. RegisterAuthenticationMethod('Negotiate', TIdSSPINTLMAuthentication); {do not localize}
  1186. gAuthRegistered := True;
  1187. end;
  1188. finalization
  1189. if gAuthRegistered then begin
  1190. UnregisterAuthenticationMethod('NTLM'); {do not localize}
  1191. UnregisterAuthenticationMethod('Negotiate'); {do not localize}
  1192. end;
  1193. FreeAndNil(gSSPIInterface);
  1194. end.