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.
27 /* Get malloc, free. */
30 /* Get memcpy, strlen. */
33 /* Get specification. */
38 #elif HAVE_GSSAPI_H /* Heimdal GSSAPI */
40 #else /* MIT GSSAPI */
41 # ifdef HAVE_GSSAPI_GSSAPI_H
42 # include <gssapi/gssapi.h>
44 # ifdef HAVE_GSSAPI_GSSAPI_GENERIC_H
45 # include <gssapi/gssapi_generic.h>
49 struct _Gsasl_gssapi_client_state
56 typedef struct _Gsasl_gssapi_client_state _Gsasl_gssapi_client_state
;
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
));
65 return GSASL_MALLOC_ERROR
;
67 state
->context
= GSS_C_NO_CONTEXT
;
68 state
->service
= GSS_C_NO_NAME
;
70 state
->qop
= GSASL_QOP_AUTH
; /* FIXME: Should be GSASL_QOP_AUTH_CONF. */
78 _gsasl_gssapi_client_step (Gsasl_session
* sctx
,
80 const char *input
, size_t input_len
,
81 char **output
, size_t * output_len
)
83 _Gsasl_gssapi_client_state
*state
= mech_data
;
86 gss_buffer_desc bufdesc
, bufdesc2
;
87 gss_buffer_t buf
= GSS_C_NO_BUFFER
;
88 OM_uint32 maj_stat
, min_stat
;
93 if (state
->service
== NULL
)
95 const char *service
, *hostname
;
97 service
= gsasl_property_get (sctx
, GSASL_SERVICE
);
99 return GSASL_NO_SERVICE
;
101 hostname
= gsasl_property_get (sctx
, GSASL_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
,
117 free (bufdesc
.value
);
118 if (GSS_ERROR (maj_stat
))
119 return GSASL_GSSAPI_IMPORT_NAME_ERROR
;
125 bufdesc
.length
= input_len
;
126 bufdesc
.value
= (void *) input
;
132 bufdesc2
.value
= NULL
;
133 maj_stat
= gss_init_sec_context (&min_stat
,
140 GSS_C_SEQUENCE_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
);
152 return GSASL_MALLOC_ERROR
;
153 memcpy (*output
, bufdesc2
.value
, bufdesc2
.length
);
155 if (maj_stat
== GSS_S_COMPLETE
)
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
;
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
;
200 /* FIXME: Fix 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
;
209 /* FIXME: Fix maxbuf. */
211 p
= gsasl_property_get (sctx
, GSASL_AUTHID
);
213 return GSASL_NO_AUTHID
;
215 bufdesc
.length
= 4 + strlen (p
);
216 bufdesc
.value
= malloc (bufdesc
.length
);
218 return GSASL_MALLOC_ERROR
;
221 char *q
= bufdesc
.value
;
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
);
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
;
249 res
= GSASL_MECHANISM_CALLED_TOO_MANY_TIMES
;
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
;
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
,
275 _gsasl_gssapi_client_encode (Gsasl_session
* sctx
,
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
;
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
,
294 state
->qop
& GSASL_QOP_AUTH_CONF
? 1 : 0,
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
);
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
))
314 return GSASL_GSSAPI_RELEASE_BUFFER_ERROR
;
319 *output_len
= input_len
;
320 *output
= malloc (input_len
);
322 return GSASL_MALLOC_ERROR
;
323 memcpy (*output
, input
, input_len
);
330 _gsasl_gssapi_client_decode (Gsasl_session
* sctx
,
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
;
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
,
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
);
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
))
367 return GSASL_GSSAPI_RELEASE_BUFFER_ERROR
;
372 *output_len
= input_len
;
373 *output
= malloc (input_len
);
375 return GSASL_MALLOC_ERROR
;
376 memcpy (*output
, input
, input_len
);