Add.
[gsasl.git] / lib / gs2 / server.c
blobd087d67c1721f23f427f4998bbfe319512d903ee
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.
23 #if HAVE_CONFIG_H
24 # include "config.h"
25 #endif
27 /* Get specification. */
28 #include "gs2.h"
30 /* Get malloc, free. */
31 #include <stdlib.h>
33 /* Get memcpy, strlen. */
34 #include <string.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 #include "gs2parser.h"
51 struct _Gsasl_gs2_server_state
53 int step;
54 gss_name_t client;
55 gss_cred_id_t cred;
56 gss_ctx_id_t context;
58 typedef struct _Gsasl_gs2_server_state _Gsasl_gs2_server_state;
60 int
61 _gsasl_gs2_server_start (Gsasl_session * sctx, void **mech_data)
63 _Gsasl_gs2_server_state *state;
64 OM_uint32 maj_stat, min_stat;
65 gss_name_t server;
66 gss_buffer_desc bufdesc;
67 const char *service;
68 const char *hostname;
70 service = gsasl_property_get (sctx, GSASL_SERVICE);
71 if (!service)
72 return GSASL_NO_SERVICE;
74 hostname = gsasl_property_get (sctx, GSASL_HOSTNAME);
75 if (!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));
88 if (state == NULL)
90 free (bufdesc.value);
91 return GSASL_MALLOC_ERROR;
94 maj_stat = gss_import_name (&min_stat, &bufdesc, GSS_C_NT_HOSTBASED_SERVICE,
95 &server);
96 free (bufdesc.value);
97 if (GSS_ERROR (maj_stat))
99 free (state);
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))
110 free (state);
111 return GSASL_GSSAPI_ACQUIRE_CRED_ERROR;
114 state->step = 0;
115 state->context = GSS_C_NO_CONTEXT;
116 state->client = NULL;
117 *mech_data = state;
119 return GSASL_OK;
123 _gsasl_gs2_server_step (Gsasl_session * sctx,
124 void *mech_data,
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;
132 gss_OID mech_type;
133 char tmp[4];
134 int res;
135 OM_uint32 ret_flags;
136 struct gs2_token tok;
138 *output = NULL;
139 *output_len = 0;
141 switch (state->step)
143 case 0:
144 if (input_len == 0)
146 res = GSASL_NEEDS_MORE;
147 break;
149 state->step++;
150 /* fall through */
152 case 1:
153 res = gs2_parser (input, input_len, &tok);
154 if (res < 0)
155 return GSASL_MECHANISM_PARSE_ERROR;
157 bufdesc1.value = tok.context_token;
158 bufdesc1.length = tok.context_length;
159 if (state->client)
161 gss_release_name (&min_stat, &state->client);
162 state->client = GSS_C_NO_NAME;
165 maj_stat = gss_accept_sec_context (&min_stat,
166 &state->context,
167 state->cred,
168 &bufdesc1,
169 GSS_C_NO_CHANNEL_BINDINGS,
170 &state->client,
171 &mech_type,
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)
180 puts ("prot_ready");
181 /* XXX gss_wrap token */
184 res = gs2_encode (bufdesc2.value, bufdesc2.length,
185 NULL, 0,
186 output, output_len);
187 if (res < 0)
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)
195 state->step++;
197 res = GSASL_NEEDS_MORE;
198 break;
200 case 2:
201 memset (tmp, 0xFF, 4);
202 tmp[0] = GSASL_QOP_AUTH;
203 bufdesc1.length = 4;
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);
211 if (!*output)
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;
220 state->step++;
221 res = GSASL_NEEDS_MORE;
222 break;
224 case 3:
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);
271 state->step++;
272 break;
274 default:
275 res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
276 break;
279 return res;
282 void
283 _gsasl_gs2_server_finish (Gsasl_session * sctx, void *mech_data)
285 _Gsasl_gs2_server_state *state = mech_data;
286 OM_uint32 min_stat;
288 if (!state)
289 return;
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);
300 free (state);