krb5_gssapi.c
Go to the documentation of this file.
1 /***************************************************************************
2  * _ _ ____ _
3  * Project ___| | | | _ \| |
4  * / __| | | | |_) | |
5  * | (__| |_| | _ <| |___
6  * \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 2014 - 2017, Steve Holme, <steve_holme@hotmail.com>.
9  * Copyright (C) 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
10  *
11  * This software is licensed as described in the file COPYING, which
12  * you should have received as part of this distribution. The terms
13  * are also available at https://curl.haxx.se/docs/copyright.html.
14  *
15  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
16  * copies of the Software, and permit persons to whom the Software is
17  * furnished to do so, under the terms of the COPYING file.
18  *
19  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20  * KIND, either express or implied.
21  *
22  * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism
23  *
24  ***************************************************************************/
25 
26 #include "curl_setup.h"
27 
28 #if defined(HAVE_GSSAPI) && defined(USE_KERBEROS5)
29 
30 #include <curl/curl.h>
31 
32 #include "vauth/vauth.h"
33 #include "curl_sasl.h"
34 #include "urldata.h"
35 #include "curl_base64.h"
36 #include "curl_gssapi.h"
37 #include "sendf.h"
38 #include "curl_printf.h"
39 
40 /* The last #include files should be: */
41 #include "curl_memory.h"
42 #include "memdebug.h"
43 
44 /*
45  * Curl_auth_is_gssapi_supported()
46  *
47  * This is used to evaluate if GSSAPI (Kerberos V5) is supported.
48  *
49  * Parameters: None
50  *
51  * Returns TRUE if Kerberos V5 is supported by the GSS-API library.
52  */
53 bool Curl_auth_is_gssapi_supported(void)
54 {
55  return TRUE;
56 }
57 
58 /*
59  * Curl_auth_create_gssapi_user_message()
60  *
61  * This is used to generate an already encoded GSSAPI (Kerberos V5) user token
62  * message ready for sending to the recipient.
63  *
64  * Parameters:
65  *
66  * data [in] - The session handle.
67  * userp [in] - The user name.
68  * passdwp [in] - The user's password.
69  * service [in] - The service type such as http, smtp, pop or imap.
70  * host [in[ - The host name.
71  * mutual_auth [in] - Flag specifying whether or not mutual authentication
72  * is enabled.
73  * chlg64 [in] - Pointer to the optional base64 encoded challenge
74  * message.
75  * krb5 [in/out] - The Kerberos 5 data struct being used and modified.
76  * outptr [in/out] - The address where a pointer to newly allocated memory
77  * holding the result will be stored upon completion.
78  * outlen [out] - The length of the output message.
79  *
80  * Returns CURLE_OK on success.
81  */
82 CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
83  const char *userp,
84  const char *passwdp,
85  const char *service,
86  const char *host,
87  const bool mutual_auth,
88  const char *chlg64,
89  struct kerberos5data *krb5,
90  char **outptr, size_t *outlen)
91 {
93  size_t chlglen = 0;
94  unsigned char *chlg = NULL;
95  OM_uint32 major_status;
96  OM_uint32 minor_status;
97  OM_uint32 unused_status;
99  gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
100  gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
101 
102  (void) userp;
103  (void) passwdp;
104 
105  if(!krb5->spn) {
106  /* Generate our SPN */
107  char *spn = Curl_auth_build_spn(service, NULL, host);
108  if(!spn)
109  return CURLE_OUT_OF_MEMORY;
110 
111  /* Populate the SPN structure */
112  spn_token.value = spn;
113  spn_token.length = strlen(spn);
114 
115  /* Import the SPN */
116  major_status = gss_import_name(&minor_status, &spn_token,
117  GSS_C_NT_HOSTBASED_SERVICE, &krb5->spn);
118  if(GSS_ERROR(major_status)) {
119  Curl_gss_log_error(data, "gss_import_name() failed: ",
120  major_status, minor_status);
121 
122  free(spn);
123 
124  return CURLE_OUT_OF_MEMORY;
125  }
126 
127  free(spn);
128  }
129 
130  if(chlg64 && *chlg64) {
131  /* Decode the base-64 encoded challenge message */
132  if(*chlg64 != '=') {
133  result = Curl_base64_decode(chlg64, &chlg, &chlglen);
134  if(result)
135  return result;
136  }
137 
138  /* Ensure we have a valid challenge message */
139  if(!chlg) {
140  infof(data, "GSSAPI handshake failure (empty challenge message)\n");
141 
143  }
144 
145  /* Setup the challenge "input" security buffer */
146  input_token.value = chlg;
147  input_token.length = chlglen;
148  }
149 
150  major_status = Curl_gss_init_sec_context(data,
151  &minor_status,
152  &krb5->context,
153  krb5->spn,
154  &Curl_krb5_mech_oid,
156  &input_token,
157  &output_token,
158  mutual_auth,
159  NULL);
160 
161  /* Free the decoded challenge as it is not required anymore */
162  free(input_token.value);
163 
164  if(GSS_ERROR(major_status)) {
165  if(output_token.value)
166  gss_release_buffer(&unused_status, &output_token);
167 
168  Curl_gss_log_error(data, "gss_init_sec_context() failed: ",
169  major_status, minor_status);
170 
171  return CURLE_RECV_ERROR;
172  }
173 
174  if(output_token.value && output_token.length) {
175  /* Base64 encode the response */
176  result = Curl_base64_encode(data, (char *) output_token.value,
177  output_token.length, outptr, outlen);
178 
179  gss_release_buffer(&unused_status, &output_token);
180  }
181  else if(mutual_auth) {
182  *outptr = strdup("");
183  if(!*outptr)
184  result = CURLE_OUT_OF_MEMORY;
185  }
186 
187  return result;
188 }
189 
190 /*
191  * Curl_auth_create_gssapi_security_message()
192  *
193  * This is used to generate an already encoded GSSAPI (Kerberos V5) security
194  * token message ready for sending to the recipient.
195  *
196  * Parameters:
197  *
198  * data [in] - The session handle.
199  * chlg64 [in] - Pointer to the optional base64 encoded challenge message.
200  * krb5 [in/out] - The Kerberos 5 data struct being used and modified.
201  * outptr [in/out] - The address where a pointer to newly allocated memory
202  * holding the result will be stored upon completion.
203  * outlen [out] - The length of the output message.
204  *
205  * Returns CURLE_OK on success.
206  */
207 CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data,
208  const char *chlg64,
209  struct kerberos5data *krb5,
210  char **outptr,
211  size_t *outlen)
212 {
213  CURLcode result = CURLE_OK;
214  size_t chlglen = 0;
215  size_t messagelen = 0;
216  unsigned char *chlg = NULL;
217  unsigned char *message = NULL;
218  OM_uint32 major_status;
219  OM_uint32 minor_status;
220  OM_uint32 unused_status;
221  gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
222  gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
223  unsigned int indata = 0;
224  unsigned int outdata = 0;
226  unsigned int sec_layer = 0;
227  unsigned int max_size = 0;
228  gss_name_t username = GSS_C_NO_NAME;
229  gss_buffer_desc username_token;
230 
231  /* Decode the base-64 encoded input message */
232  if(strlen(chlg64) && *chlg64 != '=') {
233  result = Curl_base64_decode(chlg64, &chlg, &chlglen);
234  if(result)
235  return result;
236  }
237 
238  /* Ensure we have a valid challenge message */
239  if(!chlg) {
240  infof(data, "GSSAPI handshake failure (empty security message)\n");
241 
243  }
244 
245  /* Get the fully qualified username back from the context */
246  major_status = gss_inquire_context(&minor_status, krb5->context,
247  &username, NULL, NULL, NULL, NULL,
248  NULL, NULL);
249  if(GSS_ERROR(major_status)) {
250  Curl_gss_log_error(data, "gss_inquire_context() failed: ",
251  major_status, minor_status);
252 
253  free(chlg);
254 
255  return CURLE_OUT_OF_MEMORY;
256  }
257 
258  /* Convert the username from internal format to a displayable token */
259  major_status = gss_display_name(&minor_status, username,
260  &username_token, NULL);
261  if(GSS_ERROR(major_status)) {
262  Curl_gss_log_error(data, "gss_display_name() failed: ",
263  major_status, minor_status);
264 
265  free(chlg);
266 
267  return CURLE_OUT_OF_MEMORY;
268  }
269 
270  /* Setup the challenge "input" security buffer */
271  input_token.value = chlg;
272  input_token.length = chlglen;
273 
274  /* Decrypt the inbound challenge and obtain the qop */
275  major_status = gss_unwrap(&minor_status, krb5->context, &input_token,
276  &output_token, NULL, &qop);
277  if(GSS_ERROR(major_status)) {
278  Curl_gss_log_error(data, "gss_unwrap() failed: ",
279  major_status, minor_status);
280 
281  gss_release_buffer(&unused_status, &username_token);
282  free(chlg);
283 
285  }
286 
287  /* Not 4 octets long so fail as per RFC4752 Section 3.1 */
288  if(output_token.length != 4) {
289  infof(data, "GSSAPI handshake failure (invalid security data)\n");
290 
291  gss_release_buffer(&unused_status, &username_token);
292  free(chlg);
293 
295  }
296 
297  /* Copy the data out and free the challenge as it is not required anymore */
298  memcpy(&indata, output_token.value, 4);
299  gss_release_buffer(&unused_status, &output_token);
300  free(chlg);
301 
302  /* Extract the security layer */
303  sec_layer = indata & 0x000000FF;
304  if(!(sec_layer & GSSAUTH_P_NONE)) {
305  infof(data, "GSSAPI handshake failure (invalid security layer)\n");
306 
307  gss_release_buffer(&unused_status, &username_token);
308 
310  }
311 
312  /* Extract the maximum message size the server can receive */
313  max_size = ntohl(indata & 0xFFFFFF00);
314  if(max_size > 0) {
315  /* The server has told us it supports a maximum receive buffer, however, as
316  we don't require one unless we are encrypting data, we tell the server
317  our receive buffer is zero. */
318  max_size = 0;
319  }
320 
321  /* Allocate our message */
322  messagelen = sizeof(outdata) + username_token.length + 1;
323  message = malloc(messagelen);
324  if(!message) {
325  gss_release_buffer(&unused_status, &username_token);
326 
327  return CURLE_OUT_OF_MEMORY;
328  }
329 
330  /* Populate the message with the security layer, client supported receive
331  message size and authorization identity including the 0x00 based
332  terminator. Note: Despite RFC4752 Section 3.1 stating "The authorization
333  identity is not terminated with the zero-valued (%x00) octet." it seems
334  necessary to include it. */
335  outdata = htonl(max_size) | sec_layer;
336  memcpy(message, &outdata, sizeof(outdata));
337  memcpy(message + sizeof(outdata), username_token.value,
338  username_token.length);
339  message[messagelen - 1] = '\0';
340 
341  /* Free the username token as it is not required anymore */
342  gss_release_buffer(&unused_status, &username_token);
343 
344  /* Setup the "authentication data" security buffer */
345  input_token.value = message;
346  input_token.length = messagelen;
347 
348  /* Encrypt the data */
349  major_status = gss_wrap(&minor_status, krb5->context, 0,
350  GSS_C_QOP_DEFAULT, &input_token, NULL,
351  &output_token);
352  if(GSS_ERROR(major_status)) {
353  Curl_gss_log_error(data, "gss_wrap() failed: ",
354  major_status, minor_status);
355 
356  free(message);
357 
358  return CURLE_OUT_OF_MEMORY;
359  }
360 
361  /* Base64 encode the response */
362  result = Curl_base64_encode(data, (char *) output_token.value,
363  output_token.length, outptr, outlen);
364 
365  /* Free the output buffer */
366  gss_release_buffer(&unused_status, &output_token);
367 
368  /* Free the message buffer */
369  free(message);
370 
371  return result;
372 }
373 
374 /*
375  * Curl_auth_gssapi_cleanup()
376  *
377  * This is used to clean up the GSSAPI (Kerberos V5) specific data.
378  *
379  * Parameters:
380  *
381  * krb5 [in/out] - The Kerberos 5 data struct being cleaned up.
382  *
383  */
384 void Curl_auth_gssapi_cleanup(struct kerberos5data *krb5)
385 {
386  OM_uint32 minor_status;
387 
388  /* Free our security context */
389  if(krb5->context != GSS_C_NO_CONTEXT) {
390  gss_delete_sec_context(&minor_status, &krb5->context, GSS_C_NO_BUFFER);
391  krb5->context = GSS_C_NO_CONTEXT;
392  }
393 
394  /* Free the SPN */
395  if(krb5->spn != GSS_C_NO_NAME) {
396  gss_release_name(&minor_status, &krb5->spn);
397  krb5->spn = GSS_C_NO_NAME;
398  }
399 }
400 
401 #endif /* HAVE_GSSAPI && USE_KERBEROS5 */
#define free(ptr)
Definition: curl_memory.h:130
OM_uint32 gss_release_buffer(OM_uint32 *min, gss_buffer_t buffer)
Definition: stub_gssapi.c:239
#define GSS_C_NO_NAME
Definition: stub_gssapi.h:38
#define GSS_C_NO_CHANNEL_BINDINGS
Definition: stub_gssapi.h:42
CURLcode Curl_base64_decode(const char *src, unsigned char **outptr, size_t *outlen)
Definition: base64.c:100
OM_uint32 gss_qop_t
Definition: stub_gssapi.h:69
#define strdup(ptr)
Definition: curl_memory.h:122
CURLcode Curl_base64_encode(struct Curl_easy *data, const char *inputbuff, size_t insize, char **outptr, size_t *outlen)
Definition: base64.c:291
CURLcode
Definition: curl.h:454
OM_uint32 gss_display_name(OM_uint32 *min, gss_const_name_t input_name, gss_buffer_t output_name_buffer, gss_OID *output_name_type)
Definition: stub_gssapi.c:335
#define malloc(size)
Definition: curl_memory.h:124
struct gss_name_t_desc_struct * gss_name_t
Definition: stub_gssapi.h:85
UNITTEST_START int result
Definition: unit1304.c:49
#define GSS_C_NT_HOSTBASED_SERVICE
Definition: stub_gssapi.h:65
memcpy(filename, filename1, strlen(filename1))
static struct input indata[NUM_HANDLES]
Definition: http2-upload.c:183
uint32_t OM_uint32
Definition: stub_gssapi.h:67
#define GSS_ERROR(status)
Definition: stub_gssapi.h:30
Definition: curl.h:455
#define GSS_C_NO_BUFFER
Definition: stub_gssapi.h:39
OM_uint32 gss_release_name(OM_uint32 *min, gss_name_t *input_name)
Definition: stub_gssapi.c:280
char * Curl_auth_build_spn(const char *service, const char *host, const char *realm)
Definition: vauth.c:53
#define gss_delete_sec_context
Definition: setup-os400.h:183
#define gss_import_name
Definition: setup-os400.h:152
OM_uint32 gss_unwrap(OM_uint32 *min, gss_const_ctx_id_t context_handle, const gss_buffer_t input_message_buffer, gss_buffer_t output_message_buffer, int *conf_state, gss_qop_t *qop_state)
Definition: stub_gssapi.c:367
OM_uint32 gss_inquire_context(OM_uint32 *min, gss_const_ctx_id_t context_handle, gss_name_t *src_name, gss_name_t *targ_name, OM_uint32 *lifetime_rec, gss_OID *mech_type, OM_uint32 *ctx_flags, int *locally_initiated, int *open_context)
Definition: stub_gssapi.c:343
#define infof
Definition: sendf.h:44
#define TRUE
#define GSS_C_EMPTY_BUFFER
Definition: stub_gssapi.h:46
OM_uint32 gss_wrap(OM_uint32 *min, gss_const_ctx_id_t context_handle, int conf_req_flag, gss_qop_t qop_req, const gss_buffer_t input_message_buffer, int *conf_state, gss_buffer_t output_message_buffer)
Definition: stub_gssapi.c:356
#define GSS_C_QOP_DEFAULT
Definition: stub_gssapi.h:36
Definition: debug.c:29
#define GSS_C_NO_CONTEXT
Definition: stub_gssapi.h:40


rc_tagdetect_client
Author(s): Monika Florek-Jasinska , Raphael Schaller
autogenerated on Sat Feb 13 2021 03:42:15