gsasl  1.10.0
About: GNU SASL is an implementation of the Simple Authentication and Security Layer (SASL). Development version.
  Fossies Dox: gsasl-1.10.0.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

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