Add some GS2 infrastructure.
[gsasl.git] / lib / gssapi / client.c
blobf744b7040435ade05e7e7b1b5a52946ae980f9c6
1 /* client.c --- SASL mechanism GSSAPI as defined in RFC 2222, client side.
2 * Copyright (C) 2002, 2003, 2004, 2005, 2006 Simon Josefsson
4 * This file is part of GNU SASL Library.
6 * GNU SASL Library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public License
8 * as published by the Free Software Foundation; either version 2.1 of
9 * the License, or (at your option) any later version.
11 * GNU SASL Library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with GNU SASL Library; if not, write to the Free
18 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
23 #if HAVE_CONFIG_H
24 # include "config.h"
25 #endif
27 /* Get malloc, free. */
28 #include <stdlib.h>
30 /* Get memcpy, strlen. */
31 #include <string.h>
33 /* Get specification. */
34 #include "x-gssapi.h"
36 #ifdef HAVE_LIBGSS
37 # include <gss.h>
38 #elif HAVE_GSSAPI_H /* Heimdal GSSAPI */
39 # include <gssapi.h>
40 #else /* MIT GSSAPI */
41 # ifdef HAVE_GSSAPI_GSSAPI_H
42 # include <gssapi/gssapi.h>
43 # endif
44 # ifdef HAVE_GSSAPI_GSSAPI_GENERIC_H
45 # include <gssapi/gssapi_generic.h>
46 # endif
47 #endif
49 struct _Gsasl_gssapi_client_state
51 int step;
52 gss_name_t service;
53 gss_ctx_id_t context;
54 gss_qop_t qop;
56 typedef struct _Gsasl_gssapi_client_state _Gsasl_gssapi_client_state;
58 int
59 _gsasl_gssapi_client_start (Gsasl_session * sctx, void **mech_data)
61 _Gsasl_gssapi_client_state *state;
63 state = (_Gsasl_gssapi_client_state *) malloc (sizeof (*state));
64 if (state == NULL)
65 return GSASL_MALLOC_ERROR;
67 state->context = GSS_C_NO_CONTEXT;
68 state->service = GSS_C_NO_NAME;
69 state->step = 0;
70 state->qop = GSASL_QOP_AUTH; /* FIXME: Should be GSASL_QOP_AUTH_CONF. */
72 *mech_data = state;
74 return GSASL_OK;
77 int
78 _gsasl_gssapi_client_step (Gsasl_session * sctx,
79 void *mech_data,
80 const char *input, size_t input_len,
81 char **output, size_t * output_len)
83 _Gsasl_gssapi_client_state *state = mech_data;
84 char clientwrap[4];
85 gss_qop_t serverqop;
86 gss_buffer_desc bufdesc, bufdesc2;
87 gss_buffer_t buf = GSS_C_NO_BUFFER;
88 OM_uint32 maj_stat, min_stat;
89 int conf_state;
90 int res;
91 const char *p;
93 if (state->service == NULL)
95 const char *service, *hostname;
97 service = gsasl_property_get (sctx, GSASL_SERVICE);
98 if (!service)
99 return GSASL_NO_SERVICE;
101 hostname = gsasl_property_get (sctx, GSASL_HOSTNAME);
102 if (!hostname)
103 return GSASL_NO_HOSTNAME;
105 /* FIXME: Use asprintf. */
107 bufdesc.length = strlen (service) + 1 + strlen (hostname) + 1;
108 bufdesc.value = malloc (bufdesc.length);
109 if (bufdesc.value == NULL)
110 return GSASL_MALLOC_ERROR;
112 sprintf (bufdesc.value, "%s@%s", service, hostname);
114 maj_stat = gss_import_name (&min_stat, &bufdesc,
115 GSS_C_NT_HOSTBASED_SERVICE,
116 &state->service);
117 free (bufdesc.value);
118 if (GSS_ERROR (maj_stat))
119 return GSASL_GSSAPI_IMPORT_NAME_ERROR;
122 switch (state->step)
124 case 1:
125 bufdesc.length = input_len;
126 bufdesc.value = (void *) input;
127 buf = &bufdesc;
128 /* fall through */
130 case 0:
131 bufdesc2.length = 0;
132 bufdesc2.value = NULL;
133 maj_stat = gss_init_sec_context (&min_stat,
134 GSS_C_NO_CREDENTIAL,
135 &state->context,
136 state->service,
137 GSS_C_NO_OID,
138 GSS_C_MUTUAL_FLAG |
139 GSS_C_REPLAY_FLAG |
140 GSS_C_SEQUENCE_FLAG |
141 GSS_C_INTEG_FLAG |
142 GSS_C_CONF_FLAG,
144 GSS_C_NO_CHANNEL_BINDINGS,
145 buf, NULL, &bufdesc2, NULL, NULL);
146 if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED)
147 return GSASL_GSSAPI_INIT_SEC_CONTEXT_ERROR;
149 *output_len = bufdesc2.length;
150 *output = malloc (*output_len);
151 if (!*output)
152 return GSASL_MALLOC_ERROR;
153 memcpy (*output, bufdesc2.value, bufdesc2.length);
155 if (maj_stat == GSS_S_COMPLETE)
156 state->step = 2;
157 else
158 state->step = 1;
160 maj_stat = gss_release_buffer (&min_stat, &bufdesc2);
161 if (maj_stat != GSS_S_COMPLETE)
162 return GSASL_GSSAPI_RELEASE_BUFFER_ERROR;
164 res = GSASL_NEEDS_MORE;
165 break;
167 case 2:
168 /* [RFC 2222 section 7.2.1]:
169 The client passes this token to GSS_Unwrap and interprets the
170 first octet of resulting cleartext as a bit-mask specifying
171 the security layers supported by the server and the second
172 through fourth octets as the maximum size output_message to
173 send to the server. The client then constructs data, with
174 the first octet containing the bit-mask specifying the
175 selected security layer, the second through fourth octets
176 containing in network byte order the maximum size
177 output_message the client is able to receive, and the
178 remaining octets containing the authorization identity. The
179 client passes the data to GSS_Wrap with conf_flag set to
180 FALSE, and responds with the generated output_message. The
181 client can then consider the server authenticated. */
183 bufdesc.length = input_len;
184 bufdesc.value = (void *) input;
185 maj_stat = gss_unwrap (&min_stat, state->context, &bufdesc,
186 &bufdesc2, &conf_state, &serverqop);
187 if (GSS_ERROR (maj_stat))
188 return GSASL_GSSAPI_UNWRAP_ERROR;
190 if (bufdesc2.length != 4)
191 return GSASL_MECHANISM_PARSE_ERROR;
193 memcpy (clientwrap, bufdesc2.value, 4);
195 maj_stat = gss_release_buffer (&min_stat, &bufdesc2);
196 if (GSS_ERROR (maj_stat))
197 return GSASL_GSSAPI_RELEASE_BUFFER_ERROR;
199 #if 0
200 /* FIXME: Fix qop. */
201 if (cb_qop)
202 state->qop = cb_qop (sctx, serverqop);
204 if ((state->qop & serverqop) == 0)
205 /* Server does not support what user wanted. */
206 return GSASL_GSSAPI_UNSUPPORTED_PROTECTION_ERROR;
207 #endif
209 /* FIXME: Fix maxbuf. */
211 p = gsasl_property_get (sctx, GSASL_AUTHID);
212 if (!p)
213 return GSASL_NO_AUTHID;
215 bufdesc.length = 4 + strlen (p);
216 bufdesc.value = malloc (bufdesc.length);
217 if (!bufdesc.value)
218 return GSASL_MALLOC_ERROR;
221 char *q = bufdesc.value;
222 q[0] = state->qop;
223 memcpy (q + 1, clientwrap + 1, 3);
224 memcpy (q + 4, p, strlen (p));
227 maj_stat = gss_wrap (&min_stat, state->context, 0, GSS_C_QOP_DEFAULT,
228 &bufdesc, &conf_state, &bufdesc2);
229 free (bufdesc.value);
230 if (GSS_ERROR (maj_stat))
231 return GSASL_GSSAPI_WRAP_ERROR;
233 *output_len = bufdesc2.length;
234 *output = malloc (bufdesc2.length);
235 if (!*output)
236 return GSASL_MALLOC_ERROR;
238 memcpy (*output, bufdesc2.value, bufdesc2.length);
240 maj_stat = gss_release_buffer (&min_stat, &bufdesc2);
241 if (GSS_ERROR (maj_stat))
242 return GSASL_GSSAPI_RELEASE_BUFFER_ERROR;
244 state->step++;
245 res = GSASL_OK;
246 break;
248 default:
249 res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
250 break;
253 return res;
256 void
257 _gsasl_gssapi_client_finish (Gsasl_session * sctx, void *mech_data)
259 _Gsasl_gssapi_client_state *state = mech_data;
260 OM_uint32 maj_stat, min_stat;
262 if (!state)
263 return;
265 if (state->service != GSS_C_NO_NAME)
266 maj_stat = gss_release_name (&min_stat, &state->service);
267 if (state->context != GSS_C_NO_CONTEXT)
268 maj_stat = gss_delete_sec_context (&min_stat, &state->context,
269 GSS_C_NO_BUFFER);
271 free (state);
275 _gsasl_gssapi_client_encode (Gsasl_session * sctx,
276 void *mech_data,
277 const char *input, size_t input_len,
278 char **output, size_t * output_len)
280 _Gsasl_gssapi_client_state *state = mech_data;
281 OM_uint32 min_stat, maj_stat;
282 gss_buffer_desc foo;
283 gss_buffer_t input_message_buffer = &foo;
284 gss_buffer_desc output_message_buffer;
286 foo.length = input_len;
287 foo.value = (void *) input;
289 if (state && state->step == 3 &&
290 state->qop & (GSASL_QOP_AUTH_INT | GSASL_QOP_AUTH_CONF))
292 maj_stat = gss_wrap (&min_stat,
293 state->context,
294 state->qop & GSASL_QOP_AUTH_CONF ? 1 : 0,
295 GSS_C_QOP_DEFAULT,
296 input_message_buffer,
297 NULL, &output_message_buffer);
298 if (GSS_ERROR (maj_stat))
299 return GSASL_GSSAPI_WRAP_ERROR;
300 *output_len = output_message_buffer.length;
301 *output = malloc (input_len);
302 if (!*output)
304 maj_stat = gss_release_buffer (&min_stat, &output_message_buffer);
305 return GSASL_MALLOC_ERROR;
307 memcpy (*output, output_message_buffer.value,
308 output_message_buffer.length);
310 maj_stat = gss_release_buffer (&min_stat, &output_message_buffer);
311 if (GSS_ERROR (maj_stat))
313 free (*output);
314 return GSASL_GSSAPI_RELEASE_BUFFER_ERROR;
317 else
319 *output_len = input_len;
320 *output = malloc (input_len);
321 if (!*output)
322 return GSASL_MALLOC_ERROR;
323 memcpy (*output, input, input_len);
326 return GSASL_OK;
330 _gsasl_gssapi_client_decode (Gsasl_session * sctx,
331 void *mech_data,
332 const char *input, size_t input_len,
333 char **output, size_t * output_len)
335 _Gsasl_gssapi_client_state *state = mech_data;
336 OM_uint32 min_stat, maj_stat;
337 gss_buffer_desc foo;
338 gss_buffer_t input_message_buffer = &foo;
339 gss_buffer_desc output_message_buffer;
341 foo.length = input_len;
342 foo.value = (void *) input;
344 if (state && state->step == 3 &&
345 state->qop & (GSASL_QOP_AUTH_INT | GSASL_QOP_AUTH_CONF))
347 maj_stat = gss_unwrap (&min_stat,
348 state->context,
349 input_message_buffer,
350 &output_message_buffer, NULL, NULL);
351 if (GSS_ERROR (maj_stat))
352 return GSASL_GSSAPI_UNWRAP_ERROR;
353 *output_len = output_message_buffer.length;
354 *output = malloc (input_len);
355 if (!*output)
357 maj_stat = gss_release_buffer (&min_stat, &output_message_buffer);
358 return GSASL_MALLOC_ERROR;
360 memcpy (*output, output_message_buffer.value,
361 output_message_buffer.length);
363 maj_stat = gss_release_buffer (&min_stat, &output_message_buffer);
364 if (GSS_ERROR (maj_stat))
366 free (*output);
367 return GSASL_GSSAPI_RELEASE_BUFFER_ERROR;
370 else
372 *output_len = input_len;
373 *output = malloc (input_len);
374 if (!*output)
375 return GSASL_MALLOC_ERROR;
376 memcpy (*output, input, input_len);
379 return GSASL_OK;