gsasl  2.2.1
gssapi/server.c
Go to the documentation of this file.
1 /* server.c --- SASL mechanism GSSAPI as defined in RFC 4752, server side.
2  * Copyright (C) 2002-2024 Simon Josefsson
3  *
4  * This file is part of GNU SASL Library.
5  *
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.
10  *
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.
15  *
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.
20  *
21  */
22 
23 #include <config.h>
24 
25 /* Get malloc, free. */
26 #include <stdlib.h>
27 
28 /* Get memcpy, strlen. */
29 #include <string.h>
30 
31 /* Get specification. */
32 #include "x-gssapi.h"
33 
34 /* For GSS-API prototypes. */
35 #include "gss-extra.h"
36 
38 {
39  int step;
40  gss_name_t client;
41  gss_cred_id_t cred;
42  gss_ctx_id_t context;
43 };
45 
46 int
47 _gsasl_gssapi_server_start (Gsasl_session *sctx, void **mech_data)
48 {
50 
51  state = (_Gsasl_gssapi_server_state *) malloc (sizeof (*state));
52  if (state == NULL)
53  return GSASL_MALLOC_ERROR;
54 
55  state->step = 0;
56  state->cred = GSS_C_NO_CREDENTIAL;
57  state->context = GSS_C_NO_CONTEXT;
58  state->client = NULL;
59  *mech_data = state;
60 
61  return GSASL_OK;
62 }
63 
64 int
66  void *mech_data,
67  const char *input, size_t input_len,
68  char **output, size_t *output_len)
69 {
70  _Gsasl_gssapi_server_state *state = mech_data;
71  gss_buffer_desc bufdesc1, bufdesc2;
72  OM_uint32 maj_stat, min_stat;
73  gss_buffer_desc client_name;
74  gss_OID mech_type;
75  char tmp[4];
76  int res;
77 
78  *output = NULL;
79  *output_len = 0;
80 
81  switch (state->step)
82  {
83  case 0:
84  {
85  gss_name_t server;
86  const char *service;
87  const char *hostname;
88 
89  if (input_len == 0)
90  {
91  res = GSASL_NEEDS_MORE;
92  break;
93  }
94 
95  service = gsasl_property_get (sctx, GSASL_SERVICE);
96  if (!service)
97  return GSASL_NO_SERVICE;
98 
99  hostname = gsasl_property_get (sctx, GSASL_HOSTNAME);
100  if (!hostname)
101  return GSASL_NO_HOSTNAME;
102 
103  /* FIXME: Use asprintf. */
104 
105  bufdesc1.length = strlen (service) + strlen ("@")
106  + strlen (hostname) + 1;
107  bufdesc1.value = malloc (bufdesc1.length);
108  if (bufdesc1.value == NULL)
109  return GSASL_MALLOC_ERROR;
110 
111  sprintf (bufdesc1.value, "%s@%s", service, hostname);
112 
113  maj_stat = gss_import_name (&min_stat, &bufdesc1,
114  GSS_C_NT_HOSTBASED_SERVICE, &server);
115  free (bufdesc1.value);
116  if (GSS_ERROR (maj_stat))
118 
119  maj_stat = gss_acquire_cred (&min_stat, server, 0,
120  GSS_C_NULL_OID_SET, GSS_C_ACCEPT,
121  &state->cred, NULL, NULL);
122  gss_release_name (&min_stat, &server);
123  if (GSS_ERROR (maj_stat))
125  }
126  state->step++;
127  /* fall through */
128 
129  case 1:
130  bufdesc1.value = (void *) input;
131  bufdesc1.length = input_len;
132  if (state->client)
133  {
134  gss_release_name (&min_stat, &state->client);
135  state->client = GSS_C_NO_NAME;
136  }
137 
138  maj_stat = gss_accept_sec_context (&min_stat,
139  &state->context,
140  state->cred,
141  &bufdesc1,
142  GSS_C_NO_CHANNEL_BINDINGS,
143  &state->client,
144  &mech_type,
145  &bufdesc2, NULL, NULL, NULL);
146  if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED)
148 
149  if (maj_stat == GSS_S_COMPLETE)
150  state->step++;
151 
152  if (maj_stat == GSS_S_CONTINUE_NEEDED || bufdesc2.length > 0)
153  {
154  *output = malloc (bufdesc2.length);
155  if (!*output)
156  return GSASL_MALLOC_ERROR;
157  memcpy (*output, bufdesc2.value, bufdesc2.length);
158  *output_len = bufdesc2.length;
159  }
160 
161  maj_stat = gss_release_buffer (&min_stat, &bufdesc2);
162  if (GSS_ERROR (maj_stat))
164 
165  if (maj_stat == GSS_S_CONTINUE_NEEDED || *output_len > 0)
166  {
167  res = GSASL_NEEDS_MORE;
168  break;
169  }
170  /* fall through */
171 
172  case 2:
173  memset (tmp, 0xFF, 4);
174  tmp[0] = GSASL_QOP_AUTH;
175  bufdesc1.length = 4;
176  bufdesc1.value = tmp;
177  maj_stat = gss_wrap (&min_stat, state->context, 0, GSS_C_QOP_DEFAULT,
178  &bufdesc1, NULL, &bufdesc2);
179  if (GSS_ERROR (maj_stat))
181 
182  *output = malloc (bufdesc2.length);
183  if (!*output)
184  return GSASL_MALLOC_ERROR;
185  memcpy (*output, bufdesc2.value, bufdesc2.length);
186  *output_len = bufdesc2.length;
187 
188  maj_stat = gss_release_buffer (&min_stat, &bufdesc2);
189  if (GSS_ERROR (maj_stat))
191 
192  state->step++;
193  res = GSASL_NEEDS_MORE;
194  break;
195 
196  case 3:
197  bufdesc1.value = (void *) input;
198  bufdesc1.length = input_len;
199  maj_stat = gss_unwrap (&min_stat, state->context, &bufdesc1,
200  &bufdesc2, NULL, NULL);
201  if (GSS_ERROR (maj_stat))
203 
204  /* [RFC 2222 section 7.2.1]:
205  The client passes this token to GSS_Unwrap and interprets the
206  first octet of resulting cleartext as a bit-mask specifying
207  the security layers supported by the server and the second
208  through fourth octets as the maximum size output_message to
209  send to the server. The client then constructs data, with
210  the first octet containing the bit-mask specifying the
211  selected security layer, the second through fourth octets
212  containing in network byte order the maximum size
213  output_message the client is able to receive, and the
214  remaining octets containing the authorization identity. The
215  client passes the data to GSS_Wrap with conf_flag set to
216  FALSE, and responds with the generated output_message. The
217  client can then consider the server authenticated. */
218 
219  if (bufdesc2.length < 4)
221 
222  if ((((char *) bufdesc2.value)[0] & GSASL_QOP_AUTH) == 0)
223  {
224  /* Integrity or privacy unsupported */
225  maj_stat = gss_release_buffer (&min_stat, &bufdesc2);
227  }
228 
229  if (bufdesc2.length > 4)
231  (char *) bufdesc2.value + 4,
232  bufdesc2.length - 4);
233  else
234  gsasl_property_set (sctx, GSASL_AUTHZID, NULL);
235 
236  maj_stat = gss_display_name (&min_stat, state->client,
237  &client_name, &mech_type);
238  if (GSS_ERROR (maj_stat))
240 
242  client_name.value, client_name.length);
243 
244  maj_stat = gss_release_buffer (&min_stat, &client_name);
245  if (GSS_ERROR (maj_stat))
247 
248  maj_stat = gss_release_buffer (&min_stat, &bufdesc2);
249  if (GSS_ERROR (maj_stat))
251 
252  res = gsasl_callback (NULL, sctx, GSASL_VALIDATE_GSSAPI);
253 
254  state->step++;
255  break;
256 
257  default:
259  break;
260  }
261 
262  return res;
263 }
264 
265 void
267 {
268  _Gsasl_gssapi_server_state *state = mech_data;
269  OM_uint32 min_stat;
270 
271  if (!state)
272  return;
273 
274  if (state->context != GSS_C_NO_CONTEXT)
275  gss_delete_sec_context (&min_stat, &state->context, GSS_C_NO_BUFFER);
276 
277  if (state->cred != GSS_C_NO_CREDENTIAL)
278  gss_release_cred (&min_stat, &state->cred);
279 
280  if (state->client != GSS_C_NO_NAME)
281  gss_release_name (&min_stat, &state->client);
282 
283  free (state);
284 }
int gsasl_callback(Gsasl *ctx, Gsasl_session *sctx, Gsasl_property prop)
Definition: callback.c:71
@ GSASL_QOP_AUTH
Definition: gsasl.h:318
@ GSASL_GSSAPI_UNWRAP_ERROR
Definition: gsasl.h:161
@ GSASL_GSSAPI_IMPORT_NAME_ERROR
Definition: gsasl.h:158
@ GSASL_OK
Definition: gsasl.h:129
@ GSASL_GSSAPI_RELEASE_BUFFER_ERROR
Definition: gsasl.h:157
@ GSASL_GSSAPI_ACCEPT_SEC_CONTEXT_ERROR
Definition: gsasl.h:160
@ GSASL_AUTHENTICATION_ERROR
Definition: gsasl.h:138
@ GSASL_NEEDS_MORE
Definition: gsasl.h:130
@ GSASL_MALLOC_ERROR
Definition: gsasl.h:133
@ GSASL_GSSAPI_DISPLAY_NAME_ERROR
Definition: gsasl.h:164
@ GSASL_NO_SERVICE
Definition: gsasl.h:149
@ GSASL_GSSAPI_ACQUIRE_CRED_ERROR
Definition: gsasl.h:163
@ GSASL_MECHANISM_CALLED_TOO_MANY_TIMES
Definition: gsasl.h:132
@ GSASL_NO_HOSTNAME
Definition: gsasl.h:150
@ GSASL_GSSAPI_WRAP_ERROR
Definition: gsasl.h:162
@ GSASL_GSSAPI_UNSUPPORTED_PROTECTION_ERROR
Definition: gsasl.h:165
_GSASL_API int gsasl_property_set_raw(Gsasl_session *sctx, Gsasl_property prop, const char *data, size_t len)
Definition: property.c:218
_GSASL_API int gsasl_property_set(Gsasl_session *sctx, Gsasl_property prop, const char *data)
Definition: property.c:189
_GSASL_API const char * gsasl_property_get(Gsasl_session *sctx, Gsasl_property prop)
Definition: property.c:292
@ GSASL_HOSTNAME
Definition: gsasl.h:229
@ GSASL_AUTHZID
Definition: gsasl.h:225
@ GSASL_VALIDATE_GSSAPI
Definition: gsasl.h:256
@ GSASL_SERVICE
Definition: gsasl.h:228
@ GSASL_GSSAPI_DISPLAY_NAME
Definition: gsasl.h:230
void _gsasl_gssapi_server_finish(Gsasl_session *sctx, void *mech_data)
int _gsasl_gssapi_server_start(Gsasl_session *sctx, void **mech_data)
Definition: gssapi/server.c:47
int _gsasl_gssapi_server_step(Gsasl_session *sctx, void *mech_data, const char *input, size_t input_len, char **output, size_t *output_len)
Definition: gssapi/server.c:65