1*6236dae4SAndroid Build Coastguard Worker /***************************************************************************
2*6236dae4SAndroid Build Coastguard Worker * _ _ ____ _
3*6236dae4SAndroid Build Coastguard Worker * Project ___| | | | _ \| |
4*6236dae4SAndroid Build Coastguard Worker * / __| | | | |_) | |
5*6236dae4SAndroid Build Coastguard Worker * | (__| |_| | _ <| |___
6*6236dae4SAndroid Build Coastguard Worker * \___|\___/|_| \_\_____|
7*6236dae4SAndroid Build Coastguard Worker *
8*6236dae4SAndroid Build Coastguard Worker * Copyright (C) Steve Holme, <[email protected]>.
9*6236dae4SAndroid Build Coastguard Worker *
10*6236dae4SAndroid Build Coastguard Worker * This software is licensed as described in the file COPYING, which
11*6236dae4SAndroid Build Coastguard Worker * you should have received as part of this distribution. The terms
12*6236dae4SAndroid Build Coastguard Worker * are also available at https://curl.se/docs/copyright.html.
13*6236dae4SAndroid Build Coastguard Worker *
14*6236dae4SAndroid Build Coastguard Worker * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15*6236dae4SAndroid Build Coastguard Worker * copies of the Software, and permit persons to whom the Software is
16*6236dae4SAndroid Build Coastguard Worker * furnished to do so, under the terms of the COPYING file.
17*6236dae4SAndroid Build Coastguard Worker *
18*6236dae4SAndroid Build Coastguard Worker * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19*6236dae4SAndroid Build Coastguard Worker * KIND, either express or implied.
20*6236dae4SAndroid Build Coastguard Worker *
21*6236dae4SAndroid Build Coastguard Worker * SPDX-License-Identifier: curl
22*6236dae4SAndroid Build Coastguard Worker *
23*6236dae4SAndroid Build Coastguard Worker * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism
24*6236dae4SAndroid Build Coastguard Worker *
25*6236dae4SAndroid Build Coastguard Worker ***************************************************************************/
26*6236dae4SAndroid Build Coastguard Worker
27*6236dae4SAndroid Build Coastguard Worker #include "curl_setup.h"
28*6236dae4SAndroid Build Coastguard Worker
29*6236dae4SAndroid Build Coastguard Worker #if defined(USE_WINDOWS_SSPI) && defined(USE_KERBEROS5)
30*6236dae4SAndroid Build Coastguard Worker
31*6236dae4SAndroid Build Coastguard Worker #include <curl/curl.h>
32*6236dae4SAndroid Build Coastguard Worker
33*6236dae4SAndroid Build Coastguard Worker #include "vauth/vauth.h"
34*6236dae4SAndroid Build Coastguard Worker #include "urldata.h"
35*6236dae4SAndroid Build Coastguard Worker #include "warnless.h"
36*6236dae4SAndroid Build Coastguard Worker #include "curl_multibyte.h"
37*6236dae4SAndroid Build Coastguard Worker #include "sendf.h"
38*6236dae4SAndroid Build Coastguard Worker
39*6236dae4SAndroid Build Coastguard Worker /* The last #include files should be: */
40*6236dae4SAndroid Build Coastguard Worker #include "curl_memory.h"
41*6236dae4SAndroid Build Coastguard Worker #include "memdebug.h"
42*6236dae4SAndroid Build Coastguard Worker
43*6236dae4SAndroid Build Coastguard Worker /*
44*6236dae4SAndroid Build Coastguard Worker * Curl_auth_is_gssapi_supported()
45*6236dae4SAndroid Build Coastguard Worker *
46*6236dae4SAndroid Build Coastguard Worker * This is used to evaluate if GSSAPI (Kerberos V5) is supported.
47*6236dae4SAndroid Build Coastguard Worker *
48*6236dae4SAndroid Build Coastguard Worker * Parameters: None
49*6236dae4SAndroid Build Coastguard Worker *
50*6236dae4SAndroid Build Coastguard Worker * Returns TRUE if Kerberos V5 is supported by Windows SSPI.
51*6236dae4SAndroid Build Coastguard Worker */
Curl_auth_is_gssapi_supported(void)52*6236dae4SAndroid Build Coastguard Worker bool Curl_auth_is_gssapi_supported(void)
53*6236dae4SAndroid Build Coastguard Worker {
54*6236dae4SAndroid Build Coastguard Worker PSecPkgInfo SecurityPackage;
55*6236dae4SAndroid Build Coastguard Worker SECURITY_STATUS status;
56*6236dae4SAndroid Build Coastguard Worker
57*6236dae4SAndroid Build Coastguard Worker /* Query the security package for Kerberos */
58*6236dae4SAndroid Build Coastguard Worker status = Curl_pSecFn->QuerySecurityPackageInfo((TCHAR *)
59*6236dae4SAndroid Build Coastguard Worker TEXT(SP_NAME_KERBEROS),
60*6236dae4SAndroid Build Coastguard Worker &SecurityPackage);
61*6236dae4SAndroid Build Coastguard Worker
62*6236dae4SAndroid Build Coastguard Worker /* Release the package buffer as it is not required anymore */
63*6236dae4SAndroid Build Coastguard Worker if(status == SEC_E_OK) {
64*6236dae4SAndroid Build Coastguard Worker Curl_pSecFn->FreeContextBuffer(SecurityPackage);
65*6236dae4SAndroid Build Coastguard Worker }
66*6236dae4SAndroid Build Coastguard Worker
67*6236dae4SAndroid Build Coastguard Worker return (status == SEC_E_OK);
68*6236dae4SAndroid Build Coastguard Worker }
69*6236dae4SAndroid Build Coastguard Worker
70*6236dae4SAndroid Build Coastguard Worker /*
71*6236dae4SAndroid Build Coastguard Worker * Curl_auth_create_gssapi_user_message()
72*6236dae4SAndroid Build Coastguard Worker *
73*6236dae4SAndroid Build Coastguard Worker * This is used to generate an already encoded GSSAPI (Kerberos V5) user token
74*6236dae4SAndroid Build Coastguard Worker * message ready for sending to the recipient.
75*6236dae4SAndroid Build Coastguard Worker *
76*6236dae4SAndroid Build Coastguard Worker * Parameters:
77*6236dae4SAndroid Build Coastguard Worker *
78*6236dae4SAndroid Build Coastguard Worker * data [in] - The session handle.
79*6236dae4SAndroid Build Coastguard Worker * userp [in] - The username in the format User or Domain\User.
80*6236dae4SAndroid Build Coastguard Worker * passwdp [in] - The user's password.
81*6236dae4SAndroid Build Coastguard Worker * service [in] - The service type such as http, smtp, pop or imap.
82*6236dae4SAndroid Build Coastguard Worker * host [in] - The hostname.
83*6236dae4SAndroid Build Coastguard Worker * mutual_auth [in] - Flag specifying whether or not mutual authentication
84*6236dae4SAndroid Build Coastguard Worker * is enabled.
85*6236dae4SAndroid Build Coastguard Worker * chlg [in] - Optional challenge message.
86*6236dae4SAndroid Build Coastguard Worker * krb5 [in/out] - The Kerberos 5 data struct being used and modified.
87*6236dae4SAndroid Build Coastguard Worker * out [out] - The result storage.
88*6236dae4SAndroid Build Coastguard Worker *
89*6236dae4SAndroid Build Coastguard Worker * Returns CURLE_OK on success.
90*6236dae4SAndroid Build Coastguard Worker */
Curl_auth_create_gssapi_user_message(struct Curl_easy * data,const char * userp,const char * passwdp,const char * service,const char * host,const bool mutual_auth,const struct bufref * chlg,struct kerberos5data * krb5,struct bufref * out)91*6236dae4SAndroid Build Coastguard Worker CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
92*6236dae4SAndroid Build Coastguard Worker const char *userp,
93*6236dae4SAndroid Build Coastguard Worker const char *passwdp,
94*6236dae4SAndroid Build Coastguard Worker const char *service,
95*6236dae4SAndroid Build Coastguard Worker const char *host,
96*6236dae4SAndroid Build Coastguard Worker const bool mutual_auth,
97*6236dae4SAndroid Build Coastguard Worker const struct bufref *chlg,
98*6236dae4SAndroid Build Coastguard Worker struct kerberos5data *krb5,
99*6236dae4SAndroid Build Coastguard Worker struct bufref *out)
100*6236dae4SAndroid Build Coastguard Worker {
101*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
102*6236dae4SAndroid Build Coastguard Worker CtxtHandle context;
103*6236dae4SAndroid Build Coastguard Worker PSecPkgInfo SecurityPackage;
104*6236dae4SAndroid Build Coastguard Worker SecBuffer chlg_buf;
105*6236dae4SAndroid Build Coastguard Worker SecBuffer resp_buf;
106*6236dae4SAndroid Build Coastguard Worker SecBufferDesc chlg_desc;
107*6236dae4SAndroid Build Coastguard Worker SecBufferDesc resp_desc;
108*6236dae4SAndroid Build Coastguard Worker SECURITY_STATUS status;
109*6236dae4SAndroid Build Coastguard Worker unsigned long attrs;
110*6236dae4SAndroid Build Coastguard Worker TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */
111*6236dae4SAndroid Build Coastguard Worker
112*6236dae4SAndroid Build Coastguard Worker if(!krb5->spn) {
113*6236dae4SAndroid Build Coastguard Worker /* Generate our SPN */
114*6236dae4SAndroid Build Coastguard Worker krb5->spn = Curl_auth_build_spn(service, host, NULL);
115*6236dae4SAndroid Build Coastguard Worker if(!krb5->spn)
116*6236dae4SAndroid Build Coastguard Worker return CURLE_OUT_OF_MEMORY;
117*6236dae4SAndroid Build Coastguard Worker }
118*6236dae4SAndroid Build Coastguard Worker
119*6236dae4SAndroid Build Coastguard Worker if(!krb5->output_token) {
120*6236dae4SAndroid Build Coastguard Worker /* Query the security package for Kerberos */
121*6236dae4SAndroid Build Coastguard Worker status = Curl_pSecFn->QuerySecurityPackageInfo((TCHAR *)
122*6236dae4SAndroid Build Coastguard Worker TEXT(SP_NAME_KERBEROS),
123*6236dae4SAndroid Build Coastguard Worker &SecurityPackage);
124*6236dae4SAndroid Build Coastguard Worker if(status != SEC_E_OK) {
125*6236dae4SAndroid Build Coastguard Worker failf(data, "SSPI: could not get auth info");
126*6236dae4SAndroid Build Coastguard Worker return CURLE_AUTH_ERROR;
127*6236dae4SAndroid Build Coastguard Worker }
128*6236dae4SAndroid Build Coastguard Worker
129*6236dae4SAndroid Build Coastguard Worker krb5->token_max = SecurityPackage->cbMaxToken;
130*6236dae4SAndroid Build Coastguard Worker
131*6236dae4SAndroid Build Coastguard Worker /* Release the package buffer as it is not required anymore */
132*6236dae4SAndroid Build Coastguard Worker Curl_pSecFn->FreeContextBuffer(SecurityPackage);
133*6236dae4SAndroid Build Coastguard Worker
134*6236dae4SAndroid Build Coastguard Worker /* Allocate our response buffer */
135*6236dae4SAndroid Build Coastguard Worker krb5->output_token = malloc(krb5->token_max);
136*6236dae4SAndroid Build Coastguard Worker if(!krb5->output_token)
137*6236dae4SAndroid Build Coastguard Worker return CURLE_OUT_OF_MEMORY;
138*6236dae4SAndroid Build Coastguard Worker }
139*6236dae4SAndroid Build Coastguard Worker
140*6236dae4SAndroid Build Coastguard Worker if(!krb5->credentials) {
141*6236dae4SAndroid Build Coastguard Worker /* Do we have credentials to use or are we using single sign-on? */
142*6236dae4SAndroid Build Coastguard Worker if(userp && *userp) {
143*6236dae4SAndroid Build Coastguard Worker /* Populate our identity structure */
144*6236dae4SAndroid Build Coastguard Worker result = Curl_create_sspi_identity(userp, passwdp, &krb5->identity);
145*6236dae4SAndroid Build Coastguard Worker if(result)
146*6236dae4SAndroid Build Coastguard Worker return result;
147*6236dae4SAndroid Build Coastguard Worker
148*6236dae4SAndroid Build Coastguard Worker /* Allow proper cleanup of the identity structure */
149*6236dae4SAndroid Build Coastguard Worker krb5->p_identity = &krb5->identity;
150*6236dae4SAndroid Build Coastguard Worker }
151*6236dae4SAndroid Build Coastguard Worker else
152*6236dae4SAndroid Build Coastguard Worker /* Use the current Windows user */
153*6236dae4SAndroid Build Coastguard Worker krb5->p_identity = NULL;
154*6236dae4SAndroid Build Coastguard Worker
155*6236dae4SAndroid Build Coastguard Worker /* Allocate our credentials handle */
156*6236dae4SAndroid Build Coastguard Worker krb5->credentials = calloc(1, sizeof(CredHandle));
157*6236dae4SAndroid Build Coastguard Worker if(!krb5->credentials)
158*6236dae4SAndroid Build Coastguard Worker return CURLE_OUT_OF_MEMORY;
159*6236dae4SAndroid Build Coastguard Worker
160*6236dae4SAndroid Build Coastguard Worker /* Acquire our credentials handle */
161*6236dae4SAndroid Build Coastguard Worker status = Curl_pSecFn->AcquireCredentialsHandle(NULL,
162*6236dae4SAndroid Build Coastguard Worker (TCHAR *)
163*6236dae4SAndroid Build Coastguard Worker TEXT(SP_NAME_KERBEROS),
164*6236dae4SAndroid Build Coastguard Worker SECPKG_CRED_OUTBOUND, NULL,
165*6236dae4SAndroid Build Coastguard Worker krb5->p_identity, NULL, NULL,
166*6236dae4SAndroid Build Coastguard Worker krb5->credentials, &expiry);
167*6236dae4SAndroid Build Coastguard Worker if(status != SEC_E_OK)
168*6236dae4SAndroid Build Coastguard Worker return CURLE_LOGIN_DENIED;
169*6236dae4SAndroid Build Coastguard Worker
170*6236dae4SAndroid Build Coastguard Worker /* Allocate our new context handle */
171*6236dae4SAndroid Build Coastguard Worker krb5->context = calloc(1, sizeof(CtxtHandle));
172*6236dae4SAndroid Build Coastguard Worker if(!krb5->context)
173*6236dae4SAndroid Build Coastguard Worker return CURLE_OUT_OF_MEMORY;
174*6236dae4SAndroid Build Coastguard Worker }
175*6236dae4SAndroid Build Coastguard Worker
176*6236dae4SAndroid Build Coastguard Worker if(chlg) {
177*6236dae4SAndroid Build Coastguard Worker if(!Curl_bufref_len(chlg)) {
178*6236dae4SAndroid Build Coastguard Worker infof(data, "GSSAPI handshake failure (empty challenge message)");
179*6236dae4SAndroid Build Coastguard Worker return CURLE_BAD_CONTENT_ENCODING;
180*6236dae4SAndroid Build Coastguard Worker }
181*6236dae4SAndroid Build Coastguard Worker
182*6236dae4SAndroid Build Coastguard Worker /* Setup the challenge "input" security buffer */
183*6236dae4SAndroid Build Coastguard Worker chlg_desc.ulVersion = SECBUFFER_VERSION;
184*6236dae4SAndroid Build Coastguard Worker chlg_desc.cBuffers = 1;
185*6236dae4SAndroid Build Coastguard Worker chlg_desc.pBuffers = &chlg_buf;
186*6236dae4SAndroid Build Coastguard Worker chlg_buf.BufferType = SECBUFFER_TOKEN;
187*6236dae4SAndroid Build Coastguard Worker chlg_buf.pvBuffer = (void *) Curl_bufref_ptr(chlg);
188*6236dae4SAndroid Build Coastguard Worker chlg_buf.cbBuffer = curlx_uztoul(Curl_bufref_len(chlg));
189*6236dae4SAndroid Build Coastguard Worker }
190*6236dae4SAndroid Build Coastguard Worker
191*6236dae4SAndroid Build Coastguard Worker /* Setup the response "output" security buffer */
192*6236dae4SAndroid Build Coastguard Worker resp_desc.ulVersion = SECBUFFER_VERSION;
193*6236dae4SAndroid Build Coastguard Worker resp_desc.cBuffers = 1;
194*6236dae4SAndroid Build Coastguard Worker resp_desc.pBuffers = &resp_buf;
195*6236dae4SAndroid Build Coastguard Worker resp_buf.BufferType = SECBUFFER_TOKEN;
196*6236dae4SAndroid Build Coastguard Worker resp_buf.pvBuffer = krb5->output_token;
197*6236dae4SAndroid Build Coastguard Worker resp_buf.cbBuffer = curlx_uztoul(krb5->token_max);
198*6236dae4SAndroid Build Coastguard Worker
199*6236dae4SAndroid Build Coastguard Worker /* Generate our challenge-response message */
200*6236dae4SAndroid Build Coastguard Worker status = Curl_pSecFn->InitializeSecurityContext(krb5->credentials,
201*6236dae4SAndroid Build Coastguard Worker chlg ? krb5->context : NULL,
202*6236dae4SAndroid Build Coastguard Worker krb5->spn,
203*6236dae4SAndroid Build Coastguard Worker (mutual_auth ?
204*6236dae4SAndroid Build Coastguard Worker ISC_REQ_MUTUAL_AUTH : 0),
205*6236dae4SAndroid Build Coastguard Worker 0, SECURITY_NATIVE_DREP,
206*6236dae4SAndroid Build Coastguard Worker chlg ? &chlg_desc : NULL, 0,
207*6236dae4SAndroid Build Coastguard Worker &context,
208*6236dae4SAndroid Build Coastguard Worker &resp_desc, &attrs,
209*6236dae4SAndroid Build Coastguard Worker &expiry);
210*6236dae4SAndroid Build Coastguard Worker
211*6236dae4SAndroid Build Coastguard Worker if(status == SEC_E_INSUFFICIENT_MEMORY)
212*6236dae4SAndroid Build Coastguard Worker return CURLE_OUT_OF_MEMORY;
213*6236dae4SAndroid Build Coastguard Worker
214*6236dae4SAndroid Build Coastguard Worker if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED)
215*6236dae4SAndroid Build Coastguard Worker return CURLE_AUTH_ERROR;
216*6236dae4SAndroid Build Coastguard Worker
217*6236dae4SAndroid Build Coastguard Worker if(memcmp(&context, krb5->context, sizeof(context))) {
218*6236dae4SAndroid Build Coastguard Worker Curl_pSecFn->DeleteSecurityContext(krb5->context);
219*6236dae4SAndroid Build Coastguard Worker
220*6236dae4SAndroid Build Coastguard Worker memcpy(krb5->context, &context, sizeof(context));
221*6236dae4SAndroid Build Coastguard Worker }
222*6236dae4SAndroid Build Coastguard Worker
223*6236dae4SAndroid Build Coastguard Worker if(resp_buf.cbBuffer) {
224*6236dae4SAndroid Build Coastguard Worker result = Curl_bufref_memdup(out, resp_buf.pvBuffer, resp_buf.cbBuffer);
225*6236dae4SAndroid Build Coastguard Worker }
226*6236dae4SAndroid Build Coastguard Worker else if(mutual_auth)
227*6236dae4SAndroid Build Coastguard Worker Curl_bufref_set(out, "", 0, NULL);
228*6236dae4SAndroid Build Coastguard Worker else
229*6236dae4SAndroid Build Coastguard Worker Curl_bufref_set(out, NULL, 0, NULL);
230*6236dae4SAndroid Build Coastguard Worker
231*6236dae4SAndroid Build Coastguard Worker return result;
232*6236dae4SAndroid Build Coastguard Worker }
233*6236dae4SAndroid Build Coastguard Worker
234*6236dae4SAndroid Build Coastguard Worker /*
235*6236dae4SAndroid Build Coastguard Worker * Curl_auth_create_gssapi_security_message()
236*6236dae4SAndroid Build Coastguard Worker *
237*6236dae4SAndroid Build Coastguard Worker * This is used to generate an already encoded GSSAPI (Kerberos V5) security
238*6236dae4SAndroid Build Coastguard Worker * token message ready for sending to the recipient.
239*6236dae4SAndroid Build Coastguard Worker *
240*6236dae4SAndroid Build Coastguard Worker * Parameters:
241*6236dae4SAndroid Build Coastguard Worker *
242*6236dae4SAndroid Build Coastguard Worker * data [in] - The session handle.
243*6236dae4SAndroid Build Coastguard Worker * authzid [in] - The authorization identity if some.
244*6236dae4SAndroid Build Coastguard Worker * chlg [in] - The optional challenge message.
245*6236dae4SAndroid Build Coastguard Worker * krb5 [in/out] - The Kerberos 5 data struct being used and modified.
246*6236dae4SAndroid Build Coastguard Worker * out [out] - The result storage.
247*6236dae4SAndroid Build Coastguard Worker *
248*6236dae4SAndroid Build Coastguard Worker * Returns CURLE_OK on success.
249*6236dae4SAndroid Build Coastguard Worker */
Curl_auth_create_gssapi_security_message(struct Curl_easy * data,const char * authzid,const struct bufref * chlg,struct kerberos5data * krb5,struct bufref * out)250*6236dae4SAndroid Build Coastguard Worker CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data,
251*6236dae4SAndroid Build Coastguard Worker const char *authzid,
252*6236dae4SAndroid Build Coastguard Worker const struct bufref *chlg,
253*6236dae4SAndroid Build Coastguard Worker struct kerberos5data *krb5,
254*6236dae4SAndroid Build Coastguard Worker struct bufref *out)
255*6236dae4SAndroid Build Coastguard Worker {
256*6236dae4SAndroid Build Coastguard Worker size_t offset = 0;
257*6236dae4SAndroid Build Coastguard Worker size_t messagelen = 0;
258*6236dae4SAndroid Build Coastguard Worker size_t appdatalen = 0;
259*6236dae4SAndroid Build Coastguard Worker unsigned char *trailer = NULL;
260*6236dae4SAndroid Build Coastguard Worker unsigned char *message = NULL;
261*6236dae4SAndroid Build Coastguard Worker unsigned char *padding = NULL;
262*6236dae4SAndroid Build Coastguard Worker unsigned char *appdata = NULL;
263*6236dae4SAndroid Build Coastguard Worker SecBuffer input_buf[2];
264*6236dae4SAndroid Build Coastguard Worker SecBuffer wrap_buf[3];
265*6236dae4SAndroid Build Coastguard Worker SecBufferDesc input_desc;
266*6236dae4SAndroid Build Coastguard Worker SecBufferDesc wrap_desc;
267*6236dae4SAndroid Build Coastguard Worker unsigned char *indata;
268*6236dae4SAndroid Build Coastguard Worker unsigned long qop = 0;
269*6236dae4SAndroid Build Coastguard Worker unsigned long sec_layer = 0;
270*6236dae4SAndroid Build Coastguard Worker unsigned long max_size = 0;
271*6236dae4SAndroid Build Coastguard Worker SecPkgContext_Sizes sizes;
272*6236dae4SAndroid Build Coastguard Worker SECURITY_STATUS status;
273*6236dae4SAndroid Build Coastguard Worker
274*6236dae4SAndroid Build Coastguard Worker #if defined(CURL_DISABLE_VERBOSE_STRINGS)
275*6236dae4SAndroid Build Coastguard Worker (void) data;
276*6236dae4SAndroid Build Coastguard Worker #endif
277*6236dae4SAndroid Build Coastguard Worker
278*6236dae4SAndroid Build Coastguard Worker /* Ensure we have a valid challenge message */
279*6236dae4SAndroid Build Coastguard Worker if(!Curl_bufref_len(chlg)) {
280*6236dae4SAndroid Build Coastguard Worker infof(data, "GSSAPI handshake failure (empty security message)");
281*6236dae4SAndroid Build Coastguard Worker return CURLE_BAD_CONTENT_ENCODING;
282*6236dae4SAndroid Build Coastguard Worker }
283*6236dae4SAndroid Build Coastguard Worker
284*6236dae4SAndroid Build Coastguard Worker /* Get our response size information */
285*6236dae4SAndroid Build Coastguard Worker status = Curl_pSecFn->QueryContextAttributes(krb5->context,
286*6236dae4SAndroid Build Coastguard Worker SECPKG_ATTR_SIZES,
287*6236dae4SAndroid Build Coastguard Worker &sizes);
288*6236dae4SAndroid Build Coastguard Worker
289*6236dae4SAndroid Build Coastguard Worker if(status == SEC_E_INSUFFICIENT_MEMORY)
290*6236dae4SAndroid Build Coastguard Worker return CURLE_OUT_OF_MEMORY;
291*6236dae4SAndroid Build Coastguard Worker
292*6236dae4SAndroid Build Coastguard Worker if(status != SEC_E_OK)
293*6236dae4SAndroid Build Coastguard Worker return CURLE_AUTH_ERROR;
294*6236dae4SAndroid Build Coastguard Worker
295*6236dae4SAndroid Build Coastguard Worker /* Setup the "input" security buffer */
296*6236dae4SAndroid Build Coastguard Worker input_desc.ulVersion = SECBUFFER_VERSION;
297*6236dae4SAndroid Build Coastguard Worker input_desc.cBuffers = 2;
298*6236dae4SAndroid Build Coastguard Worker input_desc.pBuffers = input_buf;
299*6236dae4SAndroid Build Coastguard Worker input_buf[0].BufferType = SECBUFFER_STREAM;
300*6236dae4SAndroid Build Coastguard Worker input_buf[0].pvBuffer = (void *) Curl_bufref_ptr(chlg);
301*6236dae4SAndroid Build Coastguard Worker input_buf[0].cbBuffer = curlx_uztoul(Curl_bufref_len(chlg));
302*6236dae4SAndroid Build Coastguard Worker input_buf[1].BufferType = SECBUFFER_DATA;
303*6236dae4SAndroid Build Coastguard Worker input_buf[1].pvBuffer = NULL;
304*6236dae4SAndroid Build Coastguard Worker input_buf[1].cbBuffer = 0;
305*6236dae4SAndroid Build Coastguard Worker
306*6236dae4SAndroid Build Coastguard Worker /* Decrypt the inbound challenge and obtain the qop */
307*6236dae4SAndroid Build Coastguard Worker status = Curl_pSecFn->DecryptMessage(krb5->context, &input_desc, 0, &qop);
308*6236dae4SAndroid Build Coastguard Worker if(status != SEC_E_OK) {
309*6236dae4SAndroid Build Coastguard Worker infof(data, "GSSAPI handshake failure (empty security message)");
310*6236dae4SAndroid Build Coastguard Worker return CURLE_BAD_CONTENT_ENCODING;
311*6236dae4SAndroid Build Coastguard Worker }
312*6236dae4SAndroid Build Coastguard Worker
313*6236dae4SAndroid Build Coastguard Worker /* Not 4 octets long so fail as per RFC4752 Section 3.1 */
314*6236dae4SAndroid Build Coastguard Worker if(input_buf[1].cbBuffer != 4) {
315*6236dae4SAndroid Build Coastguard Worker infof(data, "GSSAPI handshake failure (invalid security data)");
316*6236dae4SAndroid Build Coastguard Worker return CURLE_BAD_CONTENT_ENCODING;
317*6236dae4SAndroid Build Coastguard Worker }
318*6236dae4SAndroid Build Coastguard Worker
319*6236dae4SAndroid Build Coastguard Worker /* Extract the security layer and the maximum message size */
320*6236dae4SAndroid Build Coastguard Worker indata = input_buf[1].pvBuffer;
321*6236dae4SAndroid Build Coastguard Worker sec_layer = indata[0];
322*6236dae4SAndroid Build Coastguard Worker max_size = ((unsigned long)indata[1] << 16) |
323*6236dae4SAndroid Build Coastguard Worker ((unsigned long)indata[2] << 8) | indata[3];
324*6236dae4SAndroid Build Coastguard Worker
325*6236dae4SAndroid Build Coastguard Worker /* Free the challenge as it is not required anymore */
326*6236dae4SAndroid Build Coastguard Worker Curl_pSecFn->FreeContextBuffer(input_buf[1].pvBuffer);
327*6236dae4SAndroid Build Coastguard Worker
328*6236dae4SAndroid Build Coastguard Worker /* Process the security layer */
329*6236dae4SAndroid Build Coastguard Worker if(!(sec_layer & KERB_WRAP_NO_ENCRYPT)) {
330*6236dae4SAndroid Build Coastguard Worker infof(data, "GSSAPI handshake failure (invalid security layer)");
331*6236dae4SAndroid Build Coastguard Worker return CURLE_BAD_CONTENT_ENCODING;
332*6236dae4SAndroid Build Coastguard Worker }
333*6236dae4SAndroid Build Coastguard Worker sec_layer &= KERB_WRAP_NO_ENCRYPT; /* We do not support a security layer */
334*6236dae4SAndroid Build Coastguard Worker
335*6236dae4SAndroid Build Coastguard Worker /* Process the maximum message size the server can receive */
336*6236dae4SAndroid Build Coastguard Worker if(max_size > 0) {
337*6236dae4SAndroid Build Coastguard Worker /* The server has told us it supports a maximum receive buffer, however, as
338*6236dae4SAndroid Build Coastguard Worker we do not require one unless we are encrypting data, we tell the server
339*6236dae4SAndroid Build Coastguard Worker our receive buffer is zero. */
340*6236dae4SAndroid Build Coastguard Worker max_size = 0;
341*6236dae4SAndroid Build Coastguard Worker }
342*6236dae4SAndroid Build Coastguard Worker
343*6236dae4SAndroid Build Coastguard Worker /* Allocate the trailer */
344*6236dae4SAndroid Build Coastguard Worker trailer = malloc(sizes.cbSecurityTrailer);
345*6236dae4SAndroid Build Coastguard Worker if(!trailer)
346*6236dae4SAndroid Build Coastguard Worker return CURLE_OUT_OF_MEMORY;
347*6236dae4SAndroid Build Coastguard Worker
348*6236dae4SAndroid Build Coastguard Worker /* Allocate our message */
349*6236dae4SAndroid Build Coastguard Worker messagelen = 4;
350*6236dae4SAndroid Build Coastguard Worker if(authzid)
351*6236dae4SAndroid Build Coastguard Worker messagelen += strlen(authzid);
352*6236dae4SAndroid Build Coastguard Worker message = malloc(messagelen);
353*6236dae4SAndroid Build Coastguard Worker if(!message) {
354*6236dae4SAndroid Build Coastguard Worker free(trailer);
355*6236dae4SAndroid Build Coastguard Worker
356*6236dae4SAndroid Build Coastguard Worker return CURLE_OUT_OF_MEMORY;
357*6236dae4SAndroid Build Coastguard Worker }
358*6236dae4SAndroid Build Coastguard Worker
359*6236dae4SAndroid Build Coastguard Worker /* Populate the message with the security layer and client supported receive
360*6236dae4SAndroid Build Coastguard Worker message size. */
361*6236dae4SAndroid Build Coastguard Worker message[0] = sec_layer & 0xFF;
362*6236dae4SAndroid Build Coastguard Worker message[1] = (max_size >> 16) & 0xFF;
363*6236dae4SAndroid Build Coastguard Worker message[2] = (max_size >> 8) & 0xFF;
364*6236dae4SAndroid Build Coastguard Worker message[3] = max_size & 0xFF;
365*6236dae4SAndroid Build Coastguard Worker
366*6236dae4SAndroid Build Coastguard Worker /* If given, append the authorization identity. */
367*6236dae4SAndroid Build Coastguard Worker
368*6236dae4SAndroid Build Coastguard Worker if(authzid && *authzid)
369*6236dae4SAndroid Build Coastguard Worker memcpy(message + 4, authzid, messagelen - 4);
370*6236dae4SAndroid Build Coastguard Worker
371*6236dae4SAndroid Build Coastguard Worker /* Allocate the padding */
372*6236dae4SAndroid Build Coastguard Worker padding = malloc(sizes.cbBlockSize);
373*6236dae4SAndroid Build Coastguard Worker if(!padding) {
374*6236dae4SAndroid Build Coastguard Worker free(message);
375*6236dae4SAndroid Build Coastguard Worker free(trailer);
376*6236dae4SAndroid Build Coastguard Worker
377*6236dae4SAndroid Build Coastguard Worker return CURLE_OUT_OF_MEMORY;
378*6236dae4SAndroid Build Coastguard Worker }
379*6236dae4SAndroid Build Coastguard Worker
380*6236dae4SAndroid Build Coastguard Worker /* Setup the "authentication data" security buffer */
381*6236dae4SAndroid Build Coastguard Worker wrap_desc.ulVersion = SECBUFFER_VERSION;
382*6236dae4SAndroid Build Coastguard Worker wrap_desc.cBuffers = 3;
383*6236dae4SAndroid Build Coastguard Worker wrap_desc.pBuffers = wrap_buf;
384*6236dae4SAndroid Build Coastguard Worker wrap_buf[0].BufferType = SECBUFFER_TOKEN;
385*6236dae4SAndroid Build Coastguard Worker wrap_buf[0].pvBuffer = trailer;
386*6236dae4SAndroid Build Coastguard Worker wrap_buf[0].cbBuffer = sizes.cbSecurityTrailer;
387*6236dae4SAndroid Build Coastguard Worker wrap_buf[1].BufferType = SECBUFFER_DATA;
388*6236dae4SAndroid Build Coastguard Worker wrap_buf[1].pvBuffer = message;
389*6236dae4SAndroid Build Coastguard Worker wrap_buf[1].cbBuffer = curlx_uztoul(messagelen);
390*6236dae4SAndroid Build Coastguard Worker wrap_buf[2].BufferType = SECBUFFER_PADDING;
391*6236dae4SAndroid Build Coastguard Worker wrap_buf[2].pvBuffer = padding;
392*6236dae4SAndroid Build Coastguard Worker wrap_buf[2].cbBuffer = sizes.cbBlockSize;
393*6236dae4SAndroid Build Coastguard Worker
394*6236dae4SAndroid Build Coastguard Worker /* Encrypt the data */
395*6236dae4SAndroid Build Coastguard Worker status = Curl_pSecFn->EncryptMessage(krb5->context, KERB_WRAP_NO_ENCRYPT,
396*6236dae4SAndroid Build Coastguard Worker &wrap_desc, 0);
397*6236dae4SAndroid Build Coastguard Worker if(status != SEC_E_OK) {
398*6236dae4SAndroid Build Coastguard Worker free(padding);
399*6236dae4SAndroid Build Coastguard Worker free(message);
400*6236dae4SAndroid Build Coastguard Worker free(trailer);
401*6236dae4SAndroid Build Coastguard Worker
402*6236dae4SAndroid Build Coastguard Worker if(status == SEC_E_INSUFFICIENT_MEMORY)
403*6236dae4SAndroid Build Coastguard Worker return CURLE_OUT_OF_MEMORY;
404*6236dae4SAndroid Build Coastguard Worker
405*6236dae4SAndroid Build Coastguard Worker return CURLE_AUTH_ERROR;
406*6236dae4SAndroid Build Coastguard Worker }
407*6236dae4SAndroid Build Coastguard Worker
408*6236dae4SAndroid Build Coastguard Worker /* Allocate the encryption (wrap) buffer */
409*6236dae4SAndroid Build Coastguard Worker appdatalen = wrap_buf[0].cbBuffer + wrap_buf[1].cbBuffer +
410*6236dae4SAndroid Build Coastguard Worker wrap_buf[2].cbBuffer;
411*6236dae4SAndroid Build Coastguard Worker appdata = malloc(appdatalen);
412*6236dae4SAndroid Build Coastguard Worker if(!appdata) {
413*6236dae4SAndroid Build Coastguard Worker free(padding);
414*6236dae4SAndroid Build Coastguard Worker free(message);
415*6236dae4SAndroid Build Coastguard Worker free(trailer);
416*6236dae4SAndroid Build Coastguard Worker
417*6236dae4SAndroid Build Coastguard Worker return CURLE_OUT_OF_MEMORY;
418*6236dae4SAndroid Build Coastguard Worker }
419*6236dae4SAndroid Build Coastguard Worker
420*6236dae4SAndroid Build Coastguard Worker /* Populate the encryption buffer */
421*6236dae4SAndroid Build Coastguard Worker memcpy(appdata, wrap_buf[0].pvBuffer, wrap_buf[0].cbBuffer);
422*6236dae4SAndroid Build Coastguard Worker offset += wrap_buf[0].cbBuffer;
423*6236dae4SAndroid Build Coastguard Worker memcpy(appdata + offset, wrap_buf[1].pvBuffer, wrap_buf[1].cbBuffer);
424*6236dae4SAndroid Build Coastguard Worker offset += wrap_buf[1].cbBuffer;
425*6236dae4SAndroid Build Coastguard Worker memcpy(appdata + offset, wrap_buf[2].pvBuffer, wrap_buf[2].cbBuffer);
426*6236dae4SAndroid Build Coastguard Worker
427*6236dae4SAndroid Build Coastguard Worker /* Free all of our local buffers */
428*6236dae4SAndroid Build Coastguard Worker free(padding);
429*6236dae4SAndroid Build Coastguard Worker free(message);
430*6236dae4SAndroid Build Coastguard Worker free(trailer);
431*6236dae4SAndroid Build Coastguard Worker
432*6236dae4SAndroid Build Coastguard Worker /* Return the response. */
433*6236dae4SAndroid Build Coastguard Worker Curl_bufref_set(out, appdata, appdatalen, curl_free);
434*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
435*6236dae4SAndroid Build Coastguard Worker }
436*6236dae4SAndroid Build Coastguard Worker
437*6236dae4SAndroid Build Coastguard Worker /*
438*6236dae4SAndroid Build Coastguard Worker * Curl_auth_cleanup_gssapi()
439*6236dae4SAndroid Build Coastguard Worker *
440*6236dae4SAndroid Build Coastguard Worker * This is used to clean up the GSSAPI (Kerberos V5) specific data.
441*6236dae4SAndroid Build Coastguard Worker *
442*6236dae4SAndroid Build Coastguard Worker * Parameters:
443*6236dae4SAndroid Build Coastguard Worker *
444*6236dae4SAndroid Build Coastguard Worker * krb5 [in/out] - The Kerberos 5 data struct being cleaned up.
445*6236dae4SAndroid Build Coastguard Worker *
446*6236dae4SAndroid Build Coastguard Worker */
Curl_auth_cleanup_gssapi(struct kerberos5data * krb5)447*6236dae4SAndroid Build Coastguard Worker void Curl_auth_cleanup_gssapi(struct kerberos5data *krb5)
448*6236dae4SAndroid Build Coastguard Worker {
449*6236dae4SAndroid Build Coastguard Worker /* Free our security context */
450*6236dae4SAndroid Build Coastguard Worker if(krb5->context) {
451*6236dae4SAndroid Build Coastguard Worker Curl_pSecFn->DeleteSecurityContext(krb5->context);
452*6236dae4SAndroid Build Coastguard Worker free(krb5->context);
453*6236dae4SAndroid Build Coastguard Worker krb5->context = NULL;
454*6236dae4SAndroid Build Coastguard Worker }
455*6236dae4SAndroid Build Coastguard Worker
456*6236dae4SAndroid Build Coastguard Worker /* Free our credentials handle */
457*6236dae4SAndroid Build Coastguard Worker if(krb5->credentials) {
458*6236dae4SAndroid Build Coastguard Worker Curl_pSecFn->FreeCredentialsHandle(krb5->credentials);
459*6236dae4SAndroid Build Coastguard Worker free(krb5->credentials);
460*6236dae4SAndroid Build Coastguard Worker krb5->credentials = NULL;
461*6236dae4SAndroid Build Coastguard Worker }
462*6236dae4SAndroid Build Coastguard Worker
463*6236dae4SAndroid Build Coastguard Worker /* Free our identity */
464*6236dae4SAndroid Build Coastguard Worker Curl_sspi_free_identity(krb5->p_identity);
465*6236dae4SAndroid Build Coastguard Worker krb5->p_identity = NULL;
466*6236dae4SAndroid Build Coastguard Worker
467*6236dae4SAndroid Build Coastguard Worker /* Free the SPN and output token */
468*6236dae4SAndroid Build Coastguard Worker Curl_safefree(krb5->spn);
469*6236dae4SAndroid Build Coastguard Worker Curl_safefree(krb5->output_token);
470*6236dae4SAndroid Build Coastguard Worker
471*6236dae4SAndroid Build Coastguard Worker /* Reset any variables */
472*6236dae4SAndroid Build Coastguard Worker krb5->token_max = 0;
473*6236dae4SAndroid Build Coastguard Worker }
474*6236dae4SAndroid Build Coastguard Worker
475*6236dae4SAndroid Build Coastguard Worker #endif /* USE_WINDOWS_SSPI && USE_KERBEROS5 */
476