Imported Upstream version 7.59.0
[platform/upstream/curl.git] / tests / libtest / stub_gssapi.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 2017, 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 /* Only provides the bare minimum to link with libcurl */
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29 #include "stub_gssapi.h"
30
31 #define MAX_CREDS_LENGTH 250
32 #define APPROX_TOKEN_LEN 250
33
34 enum min_err_code {
35     GSS_OK = 0,
36     GSS_NO_MEMORY,
37     GSS_INVALID_ARGS,
38     GSS_INVALID_CREDS,
39     GSS_INVALID_CTX,
40     GSS_SERVER_ERR,
41     GSS_NO_MECH,
42     GSS_LAST
43 };
44
45 const char *min_err_table[] = {
46     "stub-gss: no error",
47     "stub-gss: no memory",
48     "stub-gss: invalid arguments",
49     "stub-gss: invalid credentials",
50     "stub-gss: invalid context",
51     "stub-gss: server returned error",
52     "stub-gss: cannot find a mechanism",
53     NULL
54 };
55
56 struct gss_ctx_id_t_desc_struct {
57   enum { NONE, KRB5, NTLM1, NTLM3 } sent;
58   int have_krb5;
59   int have_ntlm;
60   OM_uint32 flags;
61   char creds[MAX_CREDS_LENGTH];
62 };
63
64 OM_uint32 gss_init_sec_context(OM_uint32 *min,
65             gss_const_cred_id_t initiator_cred_handle,
66             gss_ctx_id_t *context_handle,
67             gss_const_name_t target_name,
68             const gss_OID mech_type,
69             OM_uint32 req_flags,
70             OM_uint32 time_req,
71             const gss_channel_bindings_t input_chan_bindings,
72             const gss_buffer_t input_token,
73             gss_OID *actual_mech_type,
74             gss_buffer_t output_token,
75             OM_uint32 *ret_flags,
76             OM_uint32 *time_rec)
77 {
78   /* The token will be encoded in base64 */
79   int length = APPROX_TOKEN_LEN * 3 / 4;
80   int used = 0;
81   char *token = NULL;
82   const char *creds = NULL;
83   gss_ctx_id_t ctx = NULL;
84
85   if(!min)
86     return GSS_S_FAILURE;
87
88   *min = 0;
89
90   if(!context_handle || !target_name || !output_token) {
91     *min = GSS_INVALID_ARGS;
92     return GSS_S_FAILURE;
93   }
94
95   creds = getenv("CURL_STUB_GSS_CREDS");
96   if(!creds || strlen(creds) >= MAX_CREDS_LENGTH) {
97     *min = GSS_INVALID_CREDS;
98     return GSS_S_FAILURE;
99   }
100
101   ctx = *context_handle;
102   if(ctx && strcmp(ctx->creds, creds)) {
103     *min = GSS_INVALID_CREDS;
104     return GSS_S_FAILURE;
105   }
106
107   output_token->length = 0;
108   output_token->value = NULL;
109
110   if(input_token && input_token->length) {
111     if(!ctx) {
112       *min = GSS_INVALID_CTX;
113       return GSS_S_FAILURE;
114     }
115
116     /* Server response, either D (RA==) or C (Qw==) */
117     if(((char *) input_token->value)[0] == 'D') {
118       /* Done */
119       switch(ctx->sent) {
120       case KRB5:
121       case NTLM3:
122         if(ret_flags)
123           *ret_flags = ctx->flags;
124         if(time_rec)
125           *time_rec = GSS_C_INDEFINITE;
126         return GSS_S_COMPLETE;
127       default:
128         *min = GSS_SERVER_ERR;
129         return GSS_S_FAILURE;
130       }
131     }
132
133     if(((char *) input_token->value)[0] != 'C') {
134       /* We only support Done or Continue */
135       *min = GSS_SERVER_ERR;
136       return GSS_S_FAILURE;
137     }
138
139     /* Continue */
140     switch(ctx->sent) {
141     case KRB5:
142       /* We sent KRB5 and it failed, let's try NTLM */
143       if(ctx->have_ntlm) {
144         ctx->sent = NTLM1;
145         break;
146       }
147       else {
148         *min = GSS_SERVER_ERR;
149         return GSS_S_FAILURE;
150       }
151     case NTLM1:
152       ctx->sent = NTLM3;
153       break;
154     default:
155       *min = GSS_SERVER_ERR;
156       return GSS_S_FAILURE;
157     }
158   }
159   else {
160     if(ctx) {
161       *min = GSS_INVALID_CTX;
162       return GSS_S_FAILURE;
163     }
164
165     ctx = (gss_ctx_id_t) calloc(sizeof(*ctx), 1);
166     if(!ctx) {
167       *min = GSS_NO_MEMORY;
168       return GSS_S_FAILURE;
169     }
170
171     if(strstr(creds, "KRB5"))
172       ctx->have_krb5 = 1;
173
174     if(strstr(creds, "NTLM"))
175       ctx->have_ntlm = 1;
176
177     if(ctx->have_krb5)
178       ctx->sent = KRB5;
179     else if(ctx->have_ntlm)
180       ctx->sent = NTLM1;
181     else {
182       free(ctx);
183       *min = GSS_NO_MECH;
184       return GSS_S_FAILURE;
185     }
186
187     strcpy(ctx->creds, creds);
188     ctx->flags = req_flags;
189   }
190
191   token = malloc(length);
192   if(!token) {
193     free(ctx);
194     *min = GSS_NO_MEMORY;
195     return GSS_S_FAILURE;
196   }
197
198   /* Token format: creds:target:type:padding */
199   used = snprintf(token, length, "%s:%s:%d:", creds,
200                   (char *) target_name, ctx->sent);
201
202   if(used >= length) {
203     free(token);
204     free(ctx);
205     *min = GSS_NO_MEMORY;
206     return GSS_S_FAILURE;
207   }
208
209   /* Overwrite null terminator */
210   memset(token + used, 'A', length - used);
211
212   *context_handle = ctx;
213
214   output_token->value = token;
215   output_token->length = length;
216
217   return GSS_S_CONTINUE_NEEDED;
218 }
219
220 OM_uint32 gss_delete_sec_context(OM_uint32 *min,
221                                  gss_ctx_id_t *context_handle,
222                                  gss_buffer_t output_token)
223 {
224   if(!min)
225     return GSS_S_FAILURE;
226
227   if(!context_handle) {
228     *min = GSS_INVALID_CTX;
229     return GSS_S_FAILURE;
230   }
231
232   free(*context_handle);
233   *context_handle = NULL;
234   *min = 0;
235
236   return GSS_S_COMPLETE;
237 }
238
239 OM_uint32 gss_release_buffer(OM_uint32 *min,
240                              gss_buffer_t buffer)
241 {
242   if(min)
243     *min = 0;
244
245   if(buffer && buffer->length) {
246     free(buffer->value);
247     buffer->length = 0;
248   }
249
250   return GSS_S_COMPLETE;
251 }
252
253 OM_uint32 gss_import_name(OM_uint32 *min,
254                           const gss_buffer_t input_name_buffer,
255                           const gss_OID input_name_type,
256                           gss_name_t *output_name)
257 {
258   char *name = NULL;
259
260   if(!min)
261     return GSS_S_FAILURE;
262
263   if(!input_name_buffer || !output_name) {
264     *min = GSS_INVALID_ARGS;
265     return GSS_S_FAILURE;
266   }
267
268   name = strndup(input_name_buffer->value, input_name_buffer->length);
269   if(!name) {
270     *min = GSS_NO_MEMORY;
271     return GSS_S_FAILURE;
272   }
273
274   *output_name = (gss_name_t) name;
275   *min = 0;
276
277   return GSS_S_COMPLETE;
278 }
279
280 OM_uint32 gss_release_name(OM_uint32 *min,
281                            gss_name_t *input_name)
282 {
283   if(min)
284     *min = 0;
285
286   if(input_name)
287     free(*input_name);
288
289   return GSS_S_COMPLETE;
290 }
291
292 OM_uint32 gss_display_status(OM_uint32 *min,
293                              OM_uint32 status_value,
294                              int status_type,
295                              const gss_OID mech_type,
296                              OM_uint32 *message_context,
297                              gss_buffer_t status_string)
298 {
299   const char maj_str[] = "Stub GSS error";
300   if(min)
301     *min = 0;
302
303   if(message_context)
304     *message_context = 0;
305
306   if(status_string) {
307     status_string->value = NULL;
308     status_string->length = 0;
309
310     if(status_value >= GSS_LAST)
311       return GSS_S_FAILURE;
312
313     switch(status_type) {
314       case GSS_C_GSS_CODE:
315         status_string->value = strdup(maj_str);
316         break;
317       case GSS_C_MECH_CODE:
318         status_string->value = strdup(min_err_table[status_value]);
319         break;
320       default:
321         return GSS_S_FAILURE;
322     }
323
324     if(status_string->value)
325       status_string->length = strlen(status_string->value);
326     else
327        return GSS_S_FAILURE;
328   }
329
330   return GSS_S_COMPLETE;
331 }
332
333 /* Stubs returning error */
334
335 OM_uint32 gss_display_name(OM_uint32 *min,
336                            gss_const_name_t input_name,
337                            gss_buffer_t output_name_buffer,
338                            gss_OID *output_name_type)
339 {
340   return GSS_S_FAILURE;
341 }
342
343 OM_uint32 gss_inquire_context(OM_uint32 *min,
344                               gss_const_ctx_id_t context_handle,
345                               gss_name_t *src_name,
346                               gss_name_t *targ_name,
347                               OM_uint32 *lifetime_rec,
348                               gss_OID *mech_type,
349                               OM_uint32 *ctx_flags,
350                               int *locally_initiated,
351                               int *open_context)
352 {
353   return GSS_S_FAILURE;
354 }
355
356 OM_uint32 gss_wrap(OM_uint32 *min,
357                    gss_const_ctx_id_t context_handle,
358                    int conf_req_flag,
359                    gss_qop_t qop_req,
360                    const gss_buffer_t input_message_buffer,
361                    int *conf_state,
362                    gss_buffer_t output_message_buffer)
363 {
364   return GSS_S_FAILURE;
365 }
366
367 OM_uint32 gss_unwrap(OM_uint32 *min,
368                      gss_const_ctx_id_t context_handle,
369                      const gss_buffer_t input_message_buffer,
370                      gss_buffer_t output_message_buffer,
371                      int *conf_state,
372                      gss_qop_t *qop_state)
373 {
374   return GSS_S_FAILURE;
375 }
376
377 OM_uint32 gss_seal(OM_uint32 *min,
378                    gss_ctx_id_t context_handle,
379                    int conf_req_flag,
380                    int qop_req,
381                    gss_buffer_t input_message_buffer,
382                    int *conf_state,
383                    gss_buffer_t output_message_buffer)
384 {
385   return GSS_S_FAILURE;
386 }
387
388 OM_uint32 gss_unseal(OM_uint32 *min,
389                      gss_ctx_id_t context_handle,
390                      gss_buffer_t input_message_buffer,
391                      gss_buffer_t output_message_buffer,
392                      int *conf_state,
393                      int *qop_state)
394 {
395   return GSS_S_FAILURE;
396 }
397