1 /* server.c --- SASL mechanism GS2, server 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 specification. */
30 /* Get malloc, free. */
33 /* Get memcpy, strlen. */
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 #include "gs2parser.h"
51 struct _Gsasl_gs2_server_state
58 typedef struct _Gsasl_gs2_server_state _Gsasl_gs2_server_state
;
61 _gsasl_gs2_server_start (Gsasl_session
* sctx
, void **mech_data
)
63 _Gsasl_gs2_server_state
*state
;
64 OM_uint32 maj_stat
, min_stat
;
66 gss_buffer_desc bufdesc
;
70 service
= gsasl_property_get (sctx
, GSASL_SERVICE
);
72 return GSASL_NO_SERVICE
;
74 hostname
= gsasl_property_get (sctx
, GSASL_HOSTNAME
);
76 return GSASL_NO_HOSTNAME
;
78 /* FIXME: Use asprintf. */
80 bufdesc
.length
= strlen (service
) + strlen ("@") + strlen (hostname
) + 1;
81 bufdesc
.value
= malloc (bufdesc
.length
);
82 if (bufdesc
.value
== NULL
)
83 return GSASL_MALLOC_ERROR
;
85 sprintf (bufdesc
.value
, "%s@%s", service
, hostname
);
87 state
= (_Gsasl_gs2_server_state
*) malloc (sizeof (*state
));
91 return GSASL_MALLOC_ERROR
;
94 maj_stat
= gss_import_name (&min_stat
, &bufdesc
, GSS_C_NT_HOSTBASED_SERVICE
,
97 if (GSS_ERROR (maj_stat
))
100 return GSASL_GSSAPI_IMPORT_NAME_ERROR
;
103 maj_stat
= gss_acquire_cred (&min_stat
, server
, 0,
104 GSS_C_NULL_OID_SET
, GSS_C_ACCEPT
,
105 &state
->cred
, NULL
, NULL
);
106 gss_release_name (&min_stat
, &server
);
108 if (GSS_ERROR (maj_stat
))
111 return GSASL_GSSAPI_ACQUIRE_CRED_ERROR
;
115 state
->context
= GSS_C_NO_CONTEXT
;
116 state
->client
= NULL
;
123 _gsasl_gs2_server_step (Gsasl_session
* sctx
,
125 const char *input
, size_t input_len
,
126 char **output
, size_t * output_len
)
128 _Gsasl_gs2_server_state
*state
= mech_data
;
129 gss_buffer_desc bufdesc1
, bufdesc2
;
130 OM_uint32 maj_stat
, min_stat
;
131 gss_buffer_desc client_name
;
136 struct gs2_token tok
;
146 res
= GSASL_NEEDS_MORE
;
153 res
= gs2_parser (input
, input_len
, &tok
);
155 return GSASL_MECHANISM_PARSE_ERROR
;
157 bufdesc1
.value
= tok
.context_token
;
158 bufdesc1
.length
= tok
.context_length
;
161 gss_release_name (&min_stat
, &state
->client
);
162 state
->client
= GSS_C_NO_NAME
;
165 maj_stat
= gss_accept_sec_context (&min_stat
,
169 GSS_C_NO_CHANNEL_BINDINGS
,
172 &bufdesc2
, &ret_flags
, NULL
, NULL
);
173 if (maj_stat
!= GSS_S_COMPLETE
&& maj_stat
!= GSS_S_CONTINUE_NEEDED
)
174 return GSASL_GSSAPI_ACCEPT_SEC_CONTEXT_ERROR
;
176 /* XXX check wrap token */
178 if (ret_flags
& GSS_C_PROT_READY_FLAG
)
181 /* XXX gss_wrap token */
184 res
= gs2_encode (bufdesc2
.value
, bufdesc2
.length
,
188 return GSASL_GSSAPI_INIT_SEC_CONTEXT_ERROR
;
190 maj_stat
= gss_release_buffer (&min_stat
, &bufdesc2
);
191 if (GSS_ERROR (maj_stat
))
192 return GSASL_GSSAPI_RELEASE_BUFFER_ERROR
;
194 if (maj_stat
== GSS_S_COMPLETE
)
197 res
= GSASL_NEEDS_MORE
;
201 memset (tmp
, 0xFF, 4);
202 tmp
[0] = GSASL_QOP_AUTH
;
204 bufdesc1
.value
= tmp
;
205 maj_stat
= gss_wrap (&min_stat
, state
->context
, 0, GSS_C_QOP_DEFAULT
,
206 &bufdesc1
, NULL
, &bufdesc2
);
207 if (GSS_ERROR (maj_stat
))
208 return GSASL_GSSAPI_WRAP_ERROR
;
210 *output
= malloc (bufdesc2
.length
);
212 return GSASL_MALLOC_ERROR
;
213 memcpy (*output
, bufdesc2
.value
, bufdesc2
.length
);
214 *output_len
= bufdesc2
.length
;
216 maj_stat
= gss_release_buffer (&min_stat
, &bufdesc2
);
217 if (GSS_ERROR (maj_stat
))
218 return GSASL_GSSAPI_RELEASE_BUFFER_ERROR
;
221 res
= GSASL_NEEDS_MORE
;
225 bufdesc1
.value
= (void *) input
;
226 bufdesc1
.length
= input_len
;
227 maj_stat
= gss_unwrap (&min_stat
, state
->context
, &bufdesc1
,
228 &bufdesc2
, NULL
, NULL
);
229 if (GSS_ERROR (maj_stat
))
230 return GSASL_GSSAPI_UNWRAP_ERROR
;
232 /* [RFC 2222 section 7.2.1]:
233 The client passes this token to GSS_Unwrap and interprets the
234 first octet of resulting cleartext as a bit-mask specifying
235 the security layers supported by the server and the second
236 through fourth octets as the maximum size output_message to
237 send to the server. The client then constructs data, with
238 the first octet containing the bit-mask specifying the
239 selected security layer, the second through fourth octets
240 containing in network byte order the maximum size
241 output_message the client is able to receive, and the
242 remaining octets containing the authorization identity. The
243 client passes the data to GSS_Wrap with conf_flag set to
244 FALSE, and responds with the generated output_message. The
245 client can then consider the server authenticated. */
247 if ((((char *) bufdesc2
.value
)[0] & GSASL_QOP_AUTH
) == 0)
249 /* Integrity or privacy unsupported */
250 maj_stat
= gss_release_buffer (&min_stat
, &bufdesc2
);
251 return GSASL_GSSAPI_UNSUPPORTED_PROTECTION_ERROR
;
254 gsasl_property_set_raw (sctx
, GSASL_AUTHZID
,
255 (char*)bufdesc2
.value
+ 4, bufdesc2
.length
- 4);
257 maj_stat
= gss_display_name (&min_stat
, state
->client
,
258 &client_name
, &mech_type
);
259 if (GSS_ERROR (maj_stat
))
260 return GSASL_GSSAPI_DISPLAY_NAME_ERROR
;
262 gsasl_property_set_raw (sctx
, GSASL_GSSAPI_DISPLAY_NAME
,
263 client_name
.value
, client_name
.length
);
265 maj_stat
= gss_release_buffer (&min_stat
, &bufdesc2
);
266 if (GSS_ERROR (maj_stat
))
267 return GSASL_GSSAPI_RELEASE_BUFFER_ERROR
;
269 res
= gsasl_callback (NULL
, sctx
, GSASL_VALIDATE_GSSAPI
);
275 res
= GSASL_MECHANISM_CALLED_TOO_MANY_TIMES
;
283 _gsasl_gs2_server_finish (Gsasl_session
* sctx
, void *mech_data
)
285 _Gsasl_gs2_server_state
*state
= mech_data
;
291 if (state
->context
!= GSS_C_NO_CONTEXT
)
292 gss_delete_sec_context (&min_stat
, &state
->context
, GSS_C_NO_BUFFER
);
294 if (state
->cred
!= GSS_C_NO_CREDENTIAL
)
295 gss_release_cred (&min_stat
, &state
->cred
);
297 if (state
->client
!= GSS_C_NO_NAME
)
298 gss_release_name (&min_stat
, &state
->client
);