~ubuntu-branches/ubuntu/dapper/curl/dapper-updates

« back to all changes in this revision

Viewing changes to lib/http_negotiate.c

  • Committer: Bazaar Package Importer
  • Author(s): Domenico Andreoli
  • Date: 2004-06-04 19:09:25 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20040604190925-wy048bp31320r2z6
Tags: 7.12.0.is.7.11.2-1
* Reverted to version 7.11.2 (closes: #252348).
* Disabled support for libidn (closes: #252367). This is to leave
  curl in unstable as much similar as possible to the one in testing.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
 *                                  _   _ ____  _     
 
3
 *  Project                     ___| | | |  _ \| |    
 
4
 *                             / __| | | | |_) | |    
 
5
 *                            | (__| |_| |  _ <| |___ 
 
6
 *                             \___|\___/|_| \_\_____|
 
7
 *
 
8
 * Copyright (C) 1998 - 2004, 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 http://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
 * $Id: http_negotiate.c,v 1.7 2004/01/07 09:19:35 bagder Exp $
 
22
 ***************************************************************************/
 
23
#include "setup.h"
 
24
 
 
25
#ifdef HAVE_GSSAPI
 
26
#ifdef HAVE_GSSMIT
 
27
#define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name
 
28
#endif
 
29
 
 
30
#ifndef CURL_DISABLE_HTTP
 
31
/* -- WIN32 approved -- */
 
32
#include <stdio.h>
 
33
#include <string.h>
 
34
#include <stdarg.h>
 
35
#include <stdlib.h>
 
36
#include <ctype.h>
 
37
#include <errno.h>
 
38
 
 
39
#include "urldata.h"
 
40
#include "sendf.h"
 
41
#include "strequal.h"
 
42
#include "base64.h"
 
43
#include "http_negotiate.h"
 
44
 
 
45
#define _MPRINTF_REPLACE /* use our functions only */
 
46
#include <curl/mprintf.h>
 
47
 
 
48
/* The last #include file should be: */
 
49
#ifdef CURLDEBUG
 
50
#include "memdebug.h"
 
51
#endif
 
52
 
 
53
static int
 
54
get_gss_name(struct connectdata *conn, gss_name_t *server)
 
55
{
 
56
  struct negotiatedata *neg_ctx = &conn->data->state.negotiate;
 
57
  OM_uint32 major_status, minor_status;
 
58
  gss_buffer_desc token = GSS_C_EMPTY_BUFFER;
 
59
  char name[2048];
 
60
  const char* service;
 
61
 
 
62
  /* GSSAPI implementation by Globus (known as GSI) requires the name to be
 
63
     of form "<service>/<fqdn>" instead of <service>@<fqdn> (ie. slash instead
 
64
     of at-sign). Also GSI servers are often identified as 'host' not 'khttp'.
 
65
     Change following lines if you want to use GSI */
 
66
 
 
67
  /* IIS uses the <service>@<fqdn> form but uses 'http' as the service name */
 
68
  
 
69
  if (neg_ctx->gss) 
 
70
    service = "khttp";
 
71
  else
 
72
    service = "http";
 
73
 
 
74
  token.length = strlen(service) + 1 + strlen(conn->hostname) + 1;
 
75
  if (token.length + 1 > sizeof(name))
 
76
    return EMSGSIZE;
 
77
  sprintf(name, "%s@%s", service, conn->hostname);
 
78
 
 
79
  token.value = (void *) name;
 
80
  major_status = gss_import_name(&minor_status,
 
81
                                 &token,
 
82
                                 GSS_C_NT_HOSTBASED_SERVICE,
 
83
                                 server);
 
84
 
 
85
  return GSS_ERROR(major_status) ? -1 : 0;
 
86
}
 
87
 
 
88
static void
 
89
log_gss_error(struct connectdata *conn, OM_uint32 error_status, char *prefix)
 
90
{
 
91
  OM_uint32 maj_stat, min_stat;
 
92
  OM_uint32 msg_ctx = 0;
 
93
  gss_buffer_desc status_string;
 
94
  char buf[1024];
 
95
  size_t len;
 
96
 
 
97
  snprintf(buf, sizeof(buf), "%s", prefix);
 
98
  len = strlen(buf);
 
99
  do {
 
100
    maj_stat = gss_display_status (&min_stat,
 
101
                                   error_status,
 
102
                                   GSS_C_MECH_CODE,
 
103
                                   GSS_C_NO_OID,
 
104
                                   &msg_ctx,
 
105
                                   &status_string);
 
106
    if (sizeof(buf) > len + status_string.length + 1) {
 
107
      sprintf(buf + len, ": %s", (char*) status_string.value);
 
108
      len += status_string.length;
 
109
    }
 
110
    gss_release_buffer(&min_stat, &status_string);
 
111
  } while (!GSS_ERROR(maj_stat) && msg_ctx != 0);
 
112
 
 
113
  infof(conn->data, buf);
 
114
}
 
115
 
 
116
int Curl_input_negotiate(struct connectdata *conn, char *header)
 
117
 
118
  struct negotiatedata *neg_ctx = &conn->data->state.negotiate;
 
119
  OM_uint32 major_status, minor_status, minor_status2;
 
120
  gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
 
121
  gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
 
122
  int ret;
 
123
  size_t len;
 
124
  bool gss;
 
125
  const char* protocol;
 
126
 
 
127
  while(*header && isspace((int)*header))
 
128
    header++;
 
129
  if(checkprefix("GSS-Negotiate", header)) {
 
130
    protocol = "GSS-Negotiate";
 
131
    gss = TRUE;
 
132
  }
 
133
  else if (checkprefix("Negotiate", header)) {
 
134
    protocol = "Negotiate";
 
135
    gss = FALSE;
 
136
  }
 
137
  else
 
138
    return -1;
 
139
 
 
140
  if (neg_ctx->context) {
 
141
    if (neg_ctx->gss != gss) {
 
142
      return -1;
 
143
    }
 
144
  }
 
145
  else {
 
146
    neg_ctx->protocol = protocol;
 
147
    neg_ctx->gss = gss;
 
148
  }
 
149
    
 
150
  if (neg_ctx->context && neg_ctx->status == GSS_S_COMPLETE) {
 
151
    /* We finished succesfully our part of authentication, but server
 
152
     * rejected it (since we're again here). Exit with an error since we
 
153
     * can't invent anything better */
 
154
    Curl_cleanup_negotiate(conn->data);
 
155
    return -1;
 
156
  }
 
157
 
 
158
  if (neg_ctx->server_name == NULL &&
 
159
      (ret = get_gss_name(conn, &neg_ctx->server_name)))
 
160
    return ret;
 
161
 
 
162
  header += strlen(neg_ctx->protocol);
 
163
  while(*header && isspace((int)*header))
 
164
    header++;
 
165
 
 
166
  len = strlen(header);
 
167
  if (len > 0) {
 
168
    int rawlen;
 
169
    input_token.length = (len+3)/4 * 3;
 
170
    input_token.value = malloc(input_token.length);
 
171
    if (input_token.value == NULL)
 
172
      return ENOMEM;
 
173
    rawlen = Curl_base64_decode(header, input_token.value);
 
174
    if (rawlen < 0)
 
175
      return -1;
 
176
    input_token.length = rawlen;
 
177
 
 
178
#ifdef HAVE_SPNEGO /* Handle SPNEGO */
 
179
    if (checkprefix("Negotiate", header)) {
 
180
        ASN1_OBJECT *   object            = NULL;
 
181
        int             rc                = 1;
 
182
        unsigned char * spnegoToken       = NULL;
 
183
        size_t          spnegoTokenLength = 0;
 
184
        unsigned char * mechToken         = NULL;
 
185
        size_t          mechTokenLength   = 0;
 
186
 
 
187
        spnegoToken = malloc(input_token.length);
 
188
        if (input_token.value == NULL)
 
189
          return ENOMEM;
 
190
        spnegoTokenLength = input_token.length;
 
191
 
 
192
        object = OBJ_txt2obj ("1.2.840.113554.1.2.2", 1);
 
193
        if (!parseSpnegoTargetToken(spnegoToken,
 
194
                                    spnegoTokenLength,
 
195
                                    NULL,
 
196
                                    NULL,
 
197
                                    &mechToken,
 
198
                                    &mechTokenLength,
 
199
                                    NULL,
 
200
                                    NULL)) {
 
201
          free(spnegoToken);
 
202
          spnegoToken = NULL;
 
203
          infof(conn->data, "Parse SPNEGO Target Token failed\n");
 
204
        }
 
205
        else {
 
206
          free(input_token.value);
 
207
          input_token.value = NULL;
 
208
          input_token.value = malloc(mechTokenLength);
 
209
          memcpy(input_token.value, mechToken,mechTokenLength);
 
210
          input_token.length = mechTokenLength;
 
211
          free(mechToken);
 
212
          mechToken = NULL;
 
213
          infof(conn->data, "Parse SPNEGO Target Token succeded\n");
 
214
        }
 
215
    }
 
216
#endif
 
217
  }
 
218
 
 
219
  major_status = gss_init_sec_context(&minor_status,
 
220
                                      GSS_C_NO_CREDENTIAL,
 
221
                                      &neg_ctx->context,
 
222
                                      neg_ctx->server_name,
 
223
                                      GSS_C_NO_OID,
 
224
                                      GSS_C_DELEG_FLAG,
 
225
                                      0,
 
226
                                      GSS_C_NO_CHANNEL_BINDINGS,
 
227
                                      &input_token,
 
228
                                      NULL,
 
229
                                      &output_token,
 
230
                                      NULL,
 
231
                                      NULL);
 
232
  if (input_token.length > 0)
 
233
    gss_release_buffer(&minor_status2, &input_token);
 
234
  neg_ctx->status = major_status;
 
235
  if (GSS_ERROR(major_status)) {
 
236
    /* Curl_cleanup_negotiate(conn->data) ??? */
 
237
    log_gss_error(conn, minor_status,
 
238
                  (char *)"gss_init_sec_context() failed: ");
 
239
    return -1;
 
240
  }
 
241
 
 
242
  if (output_token.length == 0) {
 
243
    return -1;
 
244
  }
 
245
 
 
246
  neg_ctx->output_token = output_token;
 
247
  /* conn->bits.close = FALSE; */
 
248
 
 
249
  return 0;
 
250
}
 
251
   
 
252
 
 
253
CURLcode Curl_output_negotiate(struct connectdata *conn)
 
254
 
255
  struct negotiatedata *neg_ctx = &conn->data->state.negotiate;
 
256
  OM_uint32 minor_status;
 
257
  char *encoded = NULL;
 
258
  int len;
 
259
 
 
260
#ifdef HAVE_SPNEGO /* Handle SPNEGO */
 
261
  if (checkprefix("Negotiate",neg_ctx->protocol)) {
 
262
    ASN1_OBJECT *   object            = NULL;
 
263
    int             rc                = 1;
 
264
    unsigned char * spnegoToken       = NULL;
 
265
    size_t          spnegoTokenLength = 0;
 
266
    unsigned char * responseToken       = NULL;
 
267
    size_t          responseTokenLength = 0;
 
268
    
 
269
    responseToken = malloc(neg_ctx->output_token.length);
 
270
    if ( responseToken == NULL)
 
271
      return CURLE_OUT_OF_MEMORY;
 
272
    memcpy(responseToken, neg_ctx->output_token.value,
 
273
           neg_ctx->output_token.length);
 
274
    responseTokenLength = neg_ctx->output_token.length;
 
275
 
 
276
    object=OBJ_txt2obj ("1.2.840.113554.1.2.2", 1);
 
277
    if (!makeSpnegoInitialToken (object,
 
278
                                 responseToken,
 
279
                                 responseTokenLength,
 
280
                                 &spnegoToken,
 
281
                                 &spnegoTokenLength)) {
 
282
      free(responseToken);
 
283
      responseToken = NULL;
 
284
      infof(conn->data, "Make SPNEGO Initial Token failed\n");
 
285
    }
 
286
    else {
 
287
      free(neg_ctx->output_token.value);
 
288
      responseToken = NULL;
 
289
      neg_ctx->output_token.value = malloc(spnegoTokenLength);
 
290
      memcpy(neg_ctx->output_token.value, spnegoToken,spnegoTokenLength);
 
291
      neg_ctx->output_token.length = spnegoTokenLength;
 
292
      free(spnegoToken);
 
293
      spnegoToken = NULL;
 
294
      infof(conn->data, "Make SPNEGO Initial Token succeded\n");
 
295
    }
 
296
  }
 
297
#endif
 
298
  len = Curl_base64_encode(neg_ctx->output_token.value,
 
299
                           neg_ctx->output_token.length,
 
300
                           &encoded);
 
301
 
 
302
  if (len < 0)
 
303
    return CURLE_OUT_OF_MEMORY;
 
304
 
 
305
  conn->allocptr.userpwd =
 
306
    aprintf("Authorization: %s %s\r\n", neg_ctx->protocol, encoded);
 
307
  free(encoded);
 
308
  gss_release_buffer(&minor_status, &neg_ctx->output_token);
 
309
  return (conn->allocptr.userpwd == NULL) ? CURLE_OUT_OF_MEMORY : CURLE_OK;
 
310
}
 
311
 
 
312
void Curl_cleanup_negotiate(struct SessionHandle *data)
 
313
 
314
  OM_uint32 minor_status;
 
315
  struct negotiatedata *neg_ctx = &data->state.negotiate;
 
316
 
 
317
  if (neg_ctx->context != GSS_C_NO_CONTEXT)
 
318
    gss_delete_sec_context(&minor_status, &neg_ctx->context, GSS_C_NO_BUFFER);
 
319
 
 
320
  if (neg_ctx->output_token.length != 0)
 
321
    gss_release_buffer(&minor_status, &neg_ctx->output_token);
 
322
 
 
323
  if (neg_ctx->server_name != GSS_C_NO_NAME)
 
324
    gss_release_name(&minor_status, &neg_ctx->server_name);
 
325
  
 
326
  memset(neg_ctx, 0, sizeof(*neg_ctx));
 
327
}
 
328
 
 
329
 
 
330
#endif
 
331
#endif