gsasl  2.2.1
gssapi/client.c
Go to the documentation of this file.
1 /* client.c --- SASL mechanism GSSAPI as defined in RFC 4752, client 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 service;
41  gss_ctx_id_t context;
42  gss_qop_t qop;
43 };
45 
46 int
47 _gsasl_gssapi_client_start (Gsasl_session *sctx, void **mech_data)
48 {
50 
51  state = (_Gsasl_gssapi_client_state *) malloc (sizeof (*state));
52  if (state == NULL)
53  return GSASL_MALLOC_ERROR;
54 
55  state->context = GSS_C_NO_CONTEXT;
56  state->service = GSS_C_NO_NAME;
57  state->step = 0;
58  state->qop = GSASL_QOP_AUTH; /* FIXME: Should be GSASL_QOP_AUTH_CONF. */
59 
60  *mech_data = state;
61 
62  return GSASL_OK;
63 }
64 
65 int
67  void *mech_data,
68  const char *input, size_t input_len,
69  char **output, size_t *output_len)
70 {
71  _Gsasl_gssapi_client_state *state = mech_data;
72  char clientwrap[4];
73  gss_qop_t serverqop;
74  gss_buffer_desc bufdesc, bufdesc2;
75  gss_buffer_t buf = GSS_C_NO_BUFFER;
76  OM_uint32 maj_stat, min_stat;
77  int conf_state;
78  int res;
79  const char *p;
80 
81  if (state->service == NULL)
82  {
83  const char *service, *hostname;
84 
86  if (!service)
87  return GSASL_NO_SERVICE;
88 
89  hostname = gsasl_property_get (sctx, GSASL_HOSTNAME);
90  if (!hostname)
91  return GSASL_NO_HOSTNAME;
92 
93  /* FIXME: Use asprintf. */
94 
95  bufdesc.length = strlen (service) + 1 + strlen (hostname) + 1;
96  bufdesc.value = malloc (bufdesc.length);
97  if (bufdesc.value == NULL)
98  return GSASL_MALLOC_ERROR;
99 
100  sprintf (bufdesc.value, "%s@%s", service, hostname);
101 
102  maj_stat = gss_import_name (&min_stat, &bufdesc,
103  GSS_C_NT_HOSTBASED_SERVICE,
104  &state->service);
105  free (bufdesc.value);
106  if (GSS_ERROR (maj_stat))
108  }
109 
110  switch (state->step)
111  {
112  case 1:
113  bufdesc.length = input_len;
114  bufdesc.value = (void *) input;
115  buf = &bufdesc;
116  /* fall through */
117 
118  case 0:
119  bufdesc2.length = 0;
120  bufdesc2.value = NULL;
121  maj_stat = gss_init_sec_context (&min_stat,
122  GSS_C_NO_CREDENTIAL,
123  &state->context,
124  state->service,
125  GSS_C_NO_OID,
126  GSS_C_MUTUAL_FLAG |
127  GSS_C_REPLAY_FLAG |
128  GSS_C_SEQUENCE_FLAG |
129  GSS_C_INTEG_FLAG |
130  GSS_C_CONF_FLAG,
131  0,
132  GSS_C_NO_CHANNEL_BINDINGS,
133  buf, NULL, &bufdesc2, NULL, NULL);
134  if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED)
136 
137  if (bufdesc2.length > 0 && bufdesc2.value == NULL)
139 
140  *output_len = bufdesc2.length;
141  *output = malloc (*output_len);
142  if (!*output)
143  return GSASL_MALLOC_ERROR;
144  if (bufdesc2.value)
145  memcpy (*output, bufdesc2.value, bufdesc2.length);
146 
147  if (maj_stat == GSS_S_COMPLETE)
148  state->step = 2;
149  else
150  state->step = 1;
151 
152  maj_stat = gss_release_buffer (&min_stat, &bufdesc2);
153  if (maj_stat != GSS_S_COMPLETE)
155 
156  res = GSASL_NEEDS_MORE;
157  break;
158 
159  case 2:
160  /* [RFC 2222 section 7.2.1]:
161  The client passes this token to GSS_Unwrap and interprets the
162  first octet of resulting cleartext as a bit-mask specifying
163  the security layers supported by the server and the second
164  through fourth octets as the maximum size output_message to
165  send to the server. The client then constructs data, with
166  the first octet containing the bit-mask specifying the
167  selected security layer, the second through fourth octets
168  containing in network byte order the maximum size
169  output_message the client is able to receive, and the
170  remaining octets containing the authorization identity. The
171  client passes the data to GSS_Wrap with conf_flag set to
172  FALSE, and responds with the generated output_message. The
173  client can then consider the server authenticated. */
174 
175  bufdesc.length = input_len;
176  bufdesc.value = (void *) input;
177  maj_stat = gss_unwrap (&min_stat, state->context, &bufdesc,
178  &bufdesc2, &conf_state, &serverqop);
179  if (GSS_ERROR (maj_stat))
181 
182  if (bufdesc2.length != 4)
184 
185  memcpy (clientwrap, bufdesc2.value, 4);
186 
187  maj_stat = gss_release_buffer (&min_stat, &bufdesc2);
188  if (GSS_ERROR (maj_stat))
190 
191 #if 0
192  /* FIXME: Fix qop. */
193  if (cb_qop)
194  state->qop = cb_qop (sctx, serverqop);
195 
196  if ((state->qop & serverqop) == 0)
197  /* Server does not support what user wanted. */
199 #endif
200 
201  /* FIXME: Fix maxbuf. */
202 
203  p = gsasl_property_get (sctx, GSASL_AUTHZID);
204  if (!p)
205  p = "";
206 
207  bufdesc.length = 4 + strlen (p);
208  bufdesc.value = malloc (bufdesc.length);
209  if (!bufdesc.value)
210  return GSASL_MALLOC_ERROR;
211 
212  {
213  char *q = bufdesc.value;
214  q[0] = state->qop;
215  memcpy (q + 1, clientwrap + 1, 3);
216  memcpy (q + 4, p, strlen (p));
217  }
218 
219  maj_stat = gss_wrap (&min_stat, state->context, 0, GSS_C_QOP_DEFAULT,
220  &bufdesc, &conf_state, &bufdesc2);
221  free (bufdesc.value);
222  if (GSS_ERROR (maj_stat))
224 
225  *output_len = bufdesc2.length;
226  *output = malloc (bufdesc2.length);
227  if (!*output)
228  return GSASL_MALLOC_ERROR;
229 
230  memcpy (*output, bufdesc2.value, bufdesc2.length);
231 
232  maj_stat = gss_release_buffer (&min_stat, &bufdesc2);
233  if (GSS_ERROR (maj_stat))
235 
236  state->step++;
237  res = GSASL_OK;
238  break;
239 
240  default:
242  break;
243  }
244 
245  return res;
246 }
247 
248 void
250 {
251  _Gsasl_gssapi_client_state *state = mech_data;
252  OM_uint32 maj_stat, min_stat;
253 
254  if (!state)
255  return;
256 
257  if (state->service != GSS_C_NO_NAME)
258  maj_stat = gss_release_name (&min_stat, &state->service);
259  if (state->context != GSS_C_NO_CONTEXT)
260  maj_stat = gss_delete_sec_context (&min_stat, &state->context,
261  GSS_C_NO_BUFFER);
262 
263  free (state);
264 }
265 
266 int
268  void *mech_data,
269  const char *input, size_t input_len,
270  char **output, size_t *output_len)
271 {
272  _Gsasl_gssapi_client_state *state = mech_data;
273  OM_uint32 min_stat, maj_stat;
274  gss_buffer_desc foo;
275  gss_buffer_t input_message_buffer = &foo;
276  gss_buffer_desc output_message_buffer;
277 
278  foo.length = input_len;
279  foo.value = (void *) input;
280 
281  if (state && state->step == 3 &&
283  {
284  maj_stat = gss_wrap (&min_stat,
285  state->context,
286  state->qop & GSASL_QOP_AUTH_CONF ? 1 : 0,
287  GSS_C_QOP_DEFAULT,
288  input_message_buffer,
289  NULL, &output_message_buffer);
290  if (GSS_ERROR (maj_stat))
292  *output_len = output_message_buffer.length;
293  *output = malloc (output_message_buffer.length);
294  if (!*output)
295  {
296  maj_stat = gss_release_buffer (&min_stat, &output_message_buffer);
297  return GSASL_MALLOC_ERROR;
298  }
299  memcpy (*output, output_message_buffer.value,
300  output_message_buffer.length);
301 
302  maj_stat = gss_release_buffer (&min_stat, &output_message_buffer);
303  if (GSS_ERROR (maj_stat))
304  {
305  free (*output);
307  }
308  }
309  else
310  {
311  *output_len = input_len;
312  *output = malloc (input_len);
313  if (!*output)
314  return GSASL_MALLOC_ERROR;
315  memcpy (*output, input, input_len);
316  }
317 
318  return GSASL_OK;
319 }
320 
321 int
323  void *mech_data,
324  const char *input, size_t input_len,
325  char **output, size_t *output_len)
326 {
327  _Gsasl_gssapi_client_state *state = mech_data;
328  OM_uint32 min_stat, maj_stat;
329  gss_buffer_desc foo;
330  gss_buffer_t input_message_buffer = &foo;
331  gss_buffer_desc output_message_buffer;
332 
333  foo.length = input_len;
334  foo.value = (void *) input;
335 
336  if (state && state->step == 3 &&
338  {
339  maj_stat = gss_unwrap (&min_stat,
340  state->context,
341  input_message_buffer,
342  &output_message_buffer, NULL, NULL);
343  if (GSS_ERROR (maj_stat))
345  *output_len = output_message_buffer.length;
346  *output = malloc (output_message_buffer.length);
347  if (!*output)
348  {
349  maj_stat = gss_release_buffer (&min_stat, &output_message_buffer);
350  return GSASL_MALLOC_ERROR;
351  }
352  memcpy (*output, output_message_buffer.value,
353  output_message_buffer.length);
354 
355  maj_stat = gss_release_buffer (&min_stat, &output_message_buffer);
356  if (GSS_ERROR (maj_stat))
357  {
358  free (*output);
360  }
361  }
362  else
363  {
364  *output_len = input_len;
365  *output = malloc (input_len);
366  if (!*output)
367  return GSASL_MALLOC_ERROR;
368  memcpy (*output, input, input_len);
369  }
370 
371  return GSASL_OK;
372 }
@ GSASL_QOP_AUTH_CONF
Definition: gsasl.h:320
@ GSASL_QOP_AUTH
Definition: gsasl.h:318
@ GSASL_QOP_AUTH_INT
Definition: gsasl.h:319
@ 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_NEEDS_MORE
Definition: gsasl.h:130
@ GSASL_MALLOC_ERROR
Definition: gsasl.h:133
@ GSASL_NO_SERVICE
Definition: gsasl.h:149
@ 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_MECHANISM_PARSE_ERROR
Definition: gsasl.h:137
@ GSASL_GSSAPI_INIT_SEC_CONTEXT_ERROR
Definition: gsasl.h:159
@ GSASL_GSSAPI_UNSUPPORTED_PROTECTION_ERROR
Definition: gsasl.h:165
_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_SERVICE
Definition: gsasl.h:228
void _gsasl_gssapi_client_finish(Gsasl_session *sctx, void *mech_data)
int _gsasl_gssapi_client_encode(Gsasl_session *sctx, void *mech_data, const char *input, size_t input_len, char **output, size_t *output_len)
int _gsasl_gssapi_client_start(Gsasl_session *sctx, void **mech_data)
Definition: gssapi/client.c:47
int _gsasl_gssapi_client_decode(Gsasl_session *sctx, void *mech_data, const char *input, size_t input_len, char **output, size_t *output_len)
int _gsasl_gssapi_client_step(Gsasl_session *sctx, void *mech_data, const char *input, size_t input_len, char **output, size_t *output_len)
Definition: gssapi/client.c:66