| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "net/http/http_auth_handler_ntlm.h" |
| 6 |
| 7 #include "base/logging.h" |
| 8 #include "net/base/net_errors.h" |
| 9 |
| 10 #if !defined(NDEBUG) |
| 11 #define CASE_(_x) case _x: return # _x; |
| 12 static const char *MapErrorCode(int rc) { |
| 13 switch (rc) { |
| 14 CASE_(SEC_E_OK) |
| 15 CASE_(SEC_I_CONTINUE_NEEDED) |
| 16 CASE_(SEC_I_COMPLETE_NEEDED) |
| 17 CASE_(SEC_I_COMPLETE_AND_CONTINUE) |
| 18 CASE_(SEC_E_INCOMPLETE_MESSAGE) |
| 19 CASE_(SEC_I_INCOMPLETE_CREDENTIALS) |
| 20 CASE_(SEC_E_INVALID_HANDLE) |
| 21 CASE_(SEC_E_TARGET_UNKNOWN) |
| 22 CASE_(SEC_E_LOGON_DENIED) |
| 23 CASE_(SEC_E_INTERNAL_ERROR) |
| 24 CASE_(SEC_E_NO_CREDENTIALS) |
| 25 CASE_(SEC_E_NO_AUTHENTICATING_AUTHORITY) |
| 26 CASE_(SEC_E_INSUFFICIENT_MEMORY) |
| 27 CASE_(SEC_E_INVALID_TOKEN) |
| 28 } |
| 29 return "<unknown>"; |
| 30 } |
| 31 #else |
| 32 #define MapErrorCode(x) (x) |
| 33 #endif |
| 34 |
| 35 namespace net { |
| 36 |
| 37 HttpAuthHandlerNTLM::HttpAuthHandlerNTLM() |
| 38 : max_token_len_(0) { |
| 39 memset(&cred_, 0, sizeof(cred_)); |
| 40 memset(&ctxt_, 0, sizeof(ctxt_)); |
| 41 } |
| 42 |
| 43 HttpAuthHandlerNTLM::~HttpAuthHandlerNTLM() { |
| 44 ResetSecurityContext(); |
| 45 if (cred_.dwLower || cred_.dwUpper) { |
| 46 FreeCredentialHandle(&cred_); |
| 47 memset(&cred_, 0, sizeof(cred_)); |
| 48 } |
| 49 ZapString(&password_); |
| 50 } |
| 51 |
| 52 int HttpAuthHandlerNTLM::InitializeBeforeFirstChallenge() { |
| 53 DCHECK_EQ("ntlm", scheme_) << "This is not ntlm scheme"; |
| 54 |
| 55 SEC_WCHAR *package = L"NTLM"; |
| 56 PSecPkgInfo pinfo; |
| 57 TimeStamp use_before; |
| 58 SECURITY_STATUS rc; |
| 59 |
| 60 // The following API call is required to get the maximum token length |
| 61 // for the scheme. |
| 62 // TODO(arindam): Can we move this (PSecPkgInfo) to a static function ? |
| 63 rc = QuerySecurityPackageInfo(package, &pinfo); |
| 64 if (rc != SEC_E_OK) { |
| 65 LOG(ERROR) << package << " not found"; |
| 66 return ERR_UNEXPECTED; |
| 67 } |
| 68 max_token_len_ = pinfo->cbMaxToken; |
| 69 FreeContextBuffer(pinfo); |
| 70 |
| 71 SEC_WINNT_AUTH_IDENTITY identity; |
| 72 identity.Domain = |
| 73 reinterpret_cast<USHORT*>(const_cast<wchar_t*>(domain_.data())); |
| 74 identity.DomainLength = domain_.size(); |
| 75 identity.User = |
| 76 reinterpret_cast<USHORT*>(const_cast<wchar_t*>(username_.data())); |
| 77 identity.UserLength = username_.size(); |
| 78 identity.Password = |
| 79 reinterpret_cast<USHORT*>(const_cast<wchar_t*>(password_.data())); |
| 80 identity.PasswordLength = password_.size(); |
| 81 identity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE; |
| 82 |
| 83 LOG(ERROR) << "Calling Acquire Creds Handle"; |
| 84 |
| 85 // Pass the username/password to get the credentials. |
| 86 // Note: If params 1 and 5 are NULL, it gets the credentials for the |
| 87 // logged in user which can be used for single sign-on. |
| 88 rc = AcquireCredentialsHandle(const_cast<wchar_t*>(username_.c_str()), |
| 89 package, // pszPackage |
| 90 SECPKG_CRED_OUTBOUND, // fCredentialUse |
| 91 NULL, // pvLogonID |
| 92 &identity, // pAuthData (login information) |
| 93 NULL, // pGetKeyFn (always NULL) |
| 94 NULL, // pvGetKeyArgument (always NULL) |
| 95 &cred_, // phCredential |
| 96 &use_before); // ptsExpiry |
| 97 if (rc != SEC_E_OK) |
| 98 return ERR_UNEXPECTED; |
| 99 |
| 100 return OK; |
| 101 } |
| 102 |
| 103 int HttpAuthHandlerNTLM::GetNextToken(const void* in_token, |
| 104 uint32 in_token_len, |
| 105 void** out_token, |
| 106 uint32* out_token_len) { |
| 107 SECURITY_STATUS rc; |
| 108 TimeStamp ignored; |
| 109 |
| 110 DWORD ctx_attr, ctx_req = 0; |
| 111 CtxtHandle *ctx_in; |
| 112 SecBufferDesc ibd, obd; |
| 113 SecBuffer ib, ob; |
| 114 |
| 115 if (in_token) { |
| 116 ib.BufferType = SECBUFFER_TOKEN; |
| 117 ib.cbBuffer = in_token_len; |
| 118 ib.pvBuffer = const_cast<void*>(in_token); |
| 119 ibd.ulVersion = SECBUFFER_VERSION; |
| 120 ibd.cBuffers = 1; |
| 121 ibd.pBuffers = &ib; |
| 122 ctx_in = &ctxt_; |
| 123 } else { |
| 124 // If there is no input token, then we are starting a new |
| 125 // authentication sequence. If we have already initialized our |
| 126 // security context, then we're in trouble because it means that the |
| 127 // first sequence failed. We need to bail or else we might end up in |
| 128 // an infinite loop. |
| 129 if (ctxt_.dwLower || ctxt_.dwUpper) { |
| 130 LOG(ERROR) <<"Cannot restart authentication sequence"; |
| 131 return ERR_INVALID_RESPONSE; |
| 132 } |
| 133 ctx_in = NULL; |
| 134 } |
| 135 |
| 136 obd.ulVersion = SECBUFFER_VERSION; |
| 137 obd.cBuffers = 1; |
| 138 obd.pBuffers = &ob; |
| 139 ob.BufferType = SECBUFFER_TOKEN; |
| 140 ob.cbBuffer = max_token_len_; |
| 141 ob.pvBuffer = malloc(ob.cbBuffer); |
| 142 if (!ob.pvBuffer) |
| 143 return ERR_UNEXPECTED; |
| 144 memset(ob.pvBuffer, 0, ob.cbBuffer); |
| 145 |
| 146 SEC_WCHAR *sn = NULL; // Package is NTLM. |
| 147 |
| 148 LOG(ERROR) << "Sending Another Token"; |
| 149 |
| 150 // This returns a token that is passed to the remote server. |
| 151 rc = InitializeSecurityContext(&cred_, // phCredential |
| 152 ctx_in, // phContext (NULL on first call) |
| 153 sn, // pszTargetName |
| 154 ctx_req, // fContextReq |
| 155 0, // reserved NULL |
| 156 SECURITY_NATIVE_DREP, // TargetDataRep |
| 157 in_token ? &ibd : NULL, // pInput |
| 158 0, // reserved NULl |
| 159 &ctxt_, // phNewContext |
| 160 &obd, // pOutput |
| 161 &ctx_attr, // pfContextAttr |
| 162 &ignored); // ptsExpiry |
| 163 if (rc == SEC_I_CONTINUE_NEEDED || rc == SEC_E_OK) { |
| 164 if (!ob.cbBuffer) { |
| 165 free(ob.pvBuffer); |
| 166 ob.pvBuffer = NULL; |
| 167 } |
| 168 *out_token = ob.pvBuffer; |
| 169 *out_token_len = ob.cbBuffer; |
| 170 return OK; |
| 171 } else { |
| 172 LOG(ERROR) << "InitializeSecurityContext failed " << MapErrorCode(rc); |
| 173 ResetSecurityContext(); |
| 174 free(ob.pvBuffer); |
| 175 return ERR_UNEXPECTED; |
| 176 } |
| 177 } |
| 178 |
| 179 // Require identity on first pass instead of second. |
| 180 bool HttpAuthHandlerNTLM::NeedsIdentity() { |
| 181 return !auth_data_.empty(); |
| 182 } |
| 183 |
| 184 void HttpAuthHandlerNTLM::ResetSecurityContext() { |
| 185 if (ctxt_.dwLower || ctxt_.dwUpper) { |
| 186 DeleteSecurityContext(&ctxt_); |
| 187 memset(&ctxt_, 0, sizeof(ctxt_)); |
| 188 } |
| 189 } |
| 190 |
| 191 } // namespace net |
| 192 |
| OLD | NEW |