source: UsbWattMeter/trunk/curl-7.47.1/lib/http_negotiate_sspi.c

Last change on this file was 167, checked in by coas-nagasima, 8 years ago

MIMEにSJISを設定

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
  • Property svn:mime-type set to text/x-csrc; charset=SHIFT_JIS
File size: 8.9 KB
Line 
1/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
9 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at https://curl.haxx.se/docs/copyright.html.
13 *
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ***************************************************************************/
22
23#include "curl_setup.h"
24
25#ifdef USE_WINDOWS_SSPI
26
27#if !defined(CURL_DISABLE_HTTP) && defined(USE_SPNEGO)
28
29#include "urldata.h"
30#include "sendf.h"
31#include "rawstr.h"
32#include "warnless.h"
33#include "curl_base64.h"
34#include "curl_sasl.h"
35#include "http_negotiate.h"
36#include "curl_multibyte.h"
37#include "curl_printf.h"
38
39/* The last #include files should be: */
40#include "curl_memory.h"
41#include "memdebug.h"
42
43CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy,
44 const char *header)
45{
46 struct SessionHandle *data = conn->data;
47 BYTE *input_token = NULL;
48 SecBufferDesc out_buff_desc;
49 SecBuffer out_sec_buff;
50 SecBufferDesc in_buff_desc;
51 SecBuffer in_sec_buff;
52 SECURITY_STATUS status;
53 unsigned long attrs;
54 TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */
55 size_t len = 0, input_token_len = 0;
56 CURLcode result;
57
58 /* Point to the username and password */
59 const char *userp;
60 const char *passwdp;
61
62 /* Point to the correct struct with this */
63 struct negotiatedata *neg_ctx;
64
65 if(proxy) {
66 userp = conn->proxyuser;
67 passwdp = conn->proxypasswd;
68 neg_ctx = &data->state.proxyneg;
69 }
70 else {
71 userp = conn->user;
72 passwdp = conn->passwd;
73 neg_ctx = &data->state.negotiate;
74 }
75
76 /* Not set means empty */
77 if(!userp)
78 userp = "";
79
80 if(!passwdp)
81 passwdp = "";
82
83 if(neg_ctx->context && neg_ctx->status == SEC_E_OK) {
84 /* We finished successfully our part of authentication, but server
85 * rejected it (since we're again here). Exit with an error since we
86 * can't invent anything better */
87 Curl_cleanup_negotiate(data);
88 return CURLE_LOGIN_DENIED;
89 }
90
91 if(!neg_ctx->server_name) {
92 /* Check proxy auth requested but no given proxy name */
93 if(proxy && !conn->proxy.name)
94 return CURLE_BAD_FUNCTION_ARGUMENT;
95
96 /* Generate our SPN */
97 neg_ctx->server_name = Curl_sasl_build_spn(
98 proxy ? data->set.str[STRING_PROXY_SERVICE_NAME] :
99 data->set.str[STRING_SERVICE_NAME],
100 proxy ? conn->proxy.name : conn->host.name);
101 if(!neg_ctx->server_name)
102 return CURLE_OUT_OF_MEMORY;
103 }
104
105 if(!neg_ctx->output_token) {
106 PSecPkgInfo SecurityPackage;
107 status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *)
108 TEXT(SP_NAME_NEGOTIATE),
109 &SecurityPackage);
110 if(status != SEC_E_OK)
111 return CURLE_NOT_BUILT_IN;
112
113 /* Allocate input and output buffers according to the max token size
114 as indicated by the security package */
115 neg_ctx->token_max = SecurityPackage->cbMaxToken;
116 neg_ctx->output_token = malloc(neg_ctx->token_max);
117 s_pSecFn->FreeContextBuffer(SecurityPackage);
118 }
119
120 /* Obtain the input token, if any */
121 header += strlen("Negotiate");
122 while(*header && ISSPACE(*header))
123 header++;
124
125 len = strlen(header);
126 if(!len) {
127 /* Is this the first call in a new negotiation? */
128 if(neg_ctx->context) {
129 /* The server rejected our authentication and hasn't suppled any more
130 negotiation mechanisms */
131 return CURLE_LOGIN_DENIED;
132 }
133
134 /* We have to acquire credentials and allocate memory for the context */
135 neg_ctx->credentials = malloc(sizeof(CredHandle));
136 neg_ctx->context = malloc(sizeof(CtxtHandle));
137
138 if(!neg_ctx->credentials || !neg_ctx->context)
139 return CURLE_OUT_OF_MEMORY;
140
141 if(userp && *userp) {
142 /* Populate our identity structure */
143 result = Curl_create_sspi_identity(userp, passwdp, &neg_ctx->identity);
144 if(result)
145 return result;
146
147 /* Allow proper cleanup of the identity structure */
148 neg_ctx->p_identity = &neg_ctx->identity;
149 }
150 else
151 /* Use the current Windows user */
152 neg_ctx->p_identity = NULL;
153
154 /* Acquire our credientials handle */
155 neg_ctx->status =
156 s_pSecFn->AcquireCredentialsHandle(NULL,
157 (TCHAR *) TEXT(SP_NAME_NEGOTIATE),
158 SECPKG_CRED_OUTBOUND, NULL,
159 neg_ctx->p_identity, NULL, NULL,
160 neg_ctx->credentials, &expiry);
161 if(neg_ctx->status != SEC_E_OK)
162 return CURLE_LOGIN_DENIED;
163 }
164 else {
165 result = Curl_base64_decode(header,
166 (unsigned char **)&input_token,
167 &input_token_len);
168 if(result)
169 return result;
170
171 if(!input_token_len) {
172 infof(data,
173 "Negotiate handshake failure (empty challenge message)\n");
174
175 return CURLE_BAD_CONTENT_ENCODING;
176 }
177 }
178
179 /* Setup the "output" security buffer */
180 out_buff_desc.ulVersion = SECBUFFER_VERSION;
181 out_buff_desc.cBuffers = 1;
182 out_buff_desc.pBuffers = &out_sec_buff;
183 out_sec_buff.BufferType = SECBUFFER_TOKEN;
184 out_sec_buff.pvBuffer = neg_ctx->output_token;
185 out_sec_buff.cbBuffer = curlx_uztoul(neg_ctx->token_max);
186
187 /* Setup the "input" security buffer if present */
188 if(input_token) {
189 in_buff_desc.ulVersion = SECBUFFER_VERSION;
190 in_buff_desc.cBuffers = 1;
191 in_buff_desc.pBuffers = &in_sec_buff;
192 in_sec_buff.BufferType = SECBUFFER_TOKEN;
193 in_sec_buff.pvBuffer = input_token;
194 in_sec_buff.cbBuffer = curlx_uztoul(input_token_len);
195 }
196
197 /* Generate our message */
198 neg_ctx->status = s_pSecFn->InitializeSecurityContext(
199 neg_ctx->credentials,
200 input_token ? neg_ctx->context : NULL,
201 neg_ctx->server_name,
202 ISC_REQ_CONFIDENTIALITY,
203 0,
204 SECURITY_NATIVE_DREP,
205 input_token ? &in_buff_desc : NULL,
206 0,
207 neg_ctx->context,
208 &out_buff_desc,
209 &attrs,
210 &expiry);
211
212 free(input_token);
213
214 if(GSS_ERROR(neg_ctx->status))
215 return CURLE_OUT_OF_MEMORY;
216
217 if(neg_ctx->status == SEC_I_COMPLETE_NEEDED ||
218 neg_ctx->status == SEC_I_COMPLETE_AND_CONTINUE) {
219 neg_ctx->status = s_pSecFn->CompleteAuthToken(neg_ctx->context,
220 &out_buff_desc);
221 if(GSS_ERROR(neg_ctx->status))
222 return CURLE_RECV_ERROR;
223 }
224
225 neg_ctx->output_token_length = out_sec_buff.cbBuffer;
226
227 return CURLE_OK;
228}
229
230CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy)
231{
232 struct negotiatedata *neg_ctx = proxy?&conn->data->state.proxyneg:
233 &conn->data->state.negotiate;
234 char *encoded = NULL;
235 size_t len = 0;
236 char *userp;
237 CURLcode error;
238
239 error = Curl_base64_encode(conn->data,
240 (const char*)neg_ctx->output_token,
241 neg_ctx->output_token_length,
242 &encoded, &len);
243 if(error)
244 return error;
245
246 if(!len)
247 return CURLE_REMOTE_ACCESS_DENIED;
248
249 userp = aprintf("%sAuthorization: Negotiate %s\r\n", proxy ? "Proxy-" : "",
250 encoded);
251
252 if(proxy) {
253 Curl_safefree(conn->allocptr.proxyuserpwd);
254 conn->allocptr.proxyuserpwd = userp;
255 }
256 else {
257 Curl_safefree(conn->allocptr.userpwd);
258 conn->allocptr.userpwd = userp;
259 }
260 free(encoded);
261 return (userp == NULL) ? CURLE_OUT_OF_MEMORY : CURLE_OK;
262}
263
264static void cleanup(struct negotiatedata *neg_ctx)
265{
266 /* Free our security context */
267 if(neg_ctx->context) {
268 s_pSecFn->DeleteSecurityContext(neg_ctx->context);
269 free(neg_ctx->context);
270 neg_ctx->context = NULL;
271 }
272
273 /* Free our credentials handle */
274 if(neg_ctx->credentials) {
275 s_pSecFn->FreeCredentialsHandle(neg_ctx->credentials);
276 free(neg_ctx->credentials);
277 neg_ctx->credentials = NULL;
278 }
279
280 /* Free our identity */
281 Curl_sspi_free_identity(neg_ctx->p_identity);
282 neg_ctx->p_identity = NULL;
283
284 /* Free the SPN and output token */
285 Curl_safefree(neg_ctx->server_name);
286 Curl_safefree(neg_ctx->output_token);
287
288 /* Reset any variables */
289 neg_ctx->token_max = 0;
290}
291
292void Curl_cleanup_negotiate(struct SessionHandle *data)
293{
294 cleanup(&data->state.negotiate);
295 cleanup(&data->state.proxyneg);
296}
297
298#endif /* !CURL_DISABLE_HTTP && USE_SPNEGO */
299
300#endif /* USE_WINDOWS_SSPI */
Note: See TracBrowser for help on using the repository browser.