gs2/client.c

Go to the documentation of this file.
00001 /* client.c --- SASL mechanism GS2, client side.
00002  * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007  Simon Josefsson
00003  *
00004  * This file is part of GNU SASL Library.
00005  *
00006  * GNU SASL Library is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Lesser General Public License
00008  * as published by the Free Software Foundation; either version 2.1 of
00009  * the License, or (at your option) any later version.
00010  *
00011  * GNU SASL Library is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public
00017  * License along with GNU SASL Library; if not, write to the Free
00018  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019  * Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #ifdef HAVE_CONFIG_H
00024 # include "config.h"
00025 #endif
00026 
00027 /* Get specification. */
00028 #include "gs2.h"
00029 
00030 /* Get malloc, free. */
00031 #include <stdlib.h>
00032 
00033 /* Get memcpy, strlen. */
00034 #include <string.h>
00035 
00036 #ifdef HAVE_LIBGSS
00037 # include <gss.h>
00038 #elif HAVE_GSSAPI_H             /* Heimdal GSSAPI */
00039 # include <gssapi.h>
00040 #else /* MIT GSSAPI */
00041 # ifdef HAVE_GSSAPI_GSSAPI_H
00042 #  include <gssapi/gssapi.h>
00043 # endif
00044 # ifdef HAVE_GSSAPI_GSSAPI_GENERIC_H
00045 #  include <gssapi/gssapi_generic.h>
00046 # endif
00047 #endif
00048 
00049 #include "gs2parser.h"
00050 
00051 struct _gsasl_gs2_client_state
00052 {
00053   int step;
00054   gss_name_t service;
00055   gss_ctx_id_t context;
00056   gss_qop_t qop;
00057 };
00058 typedef struct _gsasl_gs2_client_state _gsasl_gs2_client_state;
00059 
00060 int
00061 _gsasl_gs2_client_start (Gsasl_session * sctx, void **mech_data)
00062 {
00063   _gsasl_gs2_client_state *state;
00064 
00065   state = (_gsasl_gs2_client_state *) malloc (sizeof (*state));
00066   if (state == NULL)
00067     return GSASL_MALLOC_ERROR;
00068 
00069   state->context = GSS_C_NO_CONTEXT;
00070   state->service = GSS_C_NO_NAME;
00071   state->step = 0;
00072   state->qop = GSASL_QOP_AUTH;  /* FIXME: Should be GSASL_QOP_AUTH_CONF. */
00073 
00074   *mech_data = state;
00075 
00076   return GSASL_OK;
00077 }
00078 
00079 int
00080 _gsasl_gs2_client_step (Gsasl_session * sctx,
00081                         void *mech_data,
00082                         const char *input, size_t input_len,
00083                         char **output, size_t * output_len)
00084 {
00085   _gsasl_gs2_client_state *state = mech_data;
00086   char clientwrap[4];
00087   gss_qop_t serverqop;
00088   gss_buffer_desc bufdesc, bufdesc2;
00089   gss_buffer_t buf = GSS_C_NO_BUFFER;
00090   OM_uint32 maj_stat, min_stat;
00091   int conf_state;
00092   int res;
00093   const char *p;
00094   OM_uint32 ret_flags;
00095   struct gs2_token tok = { NULL, 0, NULL, 0 };
00096 
00097   if (state->service == NULL)
00098     {
00099       const char *service, *hostname;
00100 
00101       service = gsasl_property_get (sctx, GSASL_SERVICE);
00102       if (!service)
00103         return GSASL_NO_SERVICE;
00104 
00105       hostname = gsasl_property_get (sctx, GSASL_HOSTNAME);
00106       if (!hostname)
00107         return GSASL_NO_HOSTNAME;
00108 
00109       /* FIXME: Use asprintf. */
00110 
00111       bufdesc.length = strlen (service) + 1 + strlen (hostname) + 1;
00112       bufdesc.value = malloc (bufdesc.length);
00113       if (bufdesc.value == NULL)
00114         return GSASL_MALLOC_ERROR;
00115 
00116       sprintf (bufdesc.value, "%s@%s", service, hostname);
00117 
00118       maj_stat = gss_import_name (&min_stat, &bufdesc,
00119                                   GSS_C_NT_HOSTBASED_SERVICE,
00120                                   &state->service);
00121       free (bufdesc.value);
00122       if (GSS_ERROR (maj_stat))
00123         return GSASL_GSSAPI_IMPORT_NAME_ERROR;
00124     }
00125 
00126   switch (state->step)
00127     {
00128     case 1:
00129       res = gs2_parser (input, input_len, &tok);
00130       if (res < 0)
00131         return GSASL_MECHANISM_PARSE_ERROR;
00132 
00133       bufdesc.length = tok.context_length;
00134       bufdesc.value = (void *) tok.context_token;
00135       buf = &bufdesc;
00136       /* fall through */
00137 
00138     case 0:
00139       bufdesc2.length = 0;
00140       bufdesc2.value = NULL;
00141       maj_stat = gss_init_sec_context (&min_stat,
00142                                        GSS_C_NO_CREDENTIAL,
00143                                        &state->context,
00144                                        state->service,
00145                                        GSS_C_NO_OID,
00146                                        GSS_C_MUTUAL_FLAG |
00147                                        GSS_C_REPLAY_FLAG |
00148                                        GSS_C_SEQUENCE_FLAG |
00149                                        GSS_C_INTEG_FLAG |
00150                                        GSS_C_CONF_FLAG,
00151                                        0,
00152                                        GSS_C_NO_CHANNEL_BINDINGS,
00153                                        buf, NULL, &bufdesc2,
00154                                        &ret_flags, NULL);
00155       if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED)
00156         return GSASL_GSSAPI_INIT_SEC_CONTEXT_ERROR;
00157 
00158       if ((ret_flags & GSS_C_PROT_READY_FLAG) || (maj_stat == GSS_S_COMPLETE))
00159         {
00160           puts ("prot_ready");
00161           /* Deal with wrap token here. */
00162           /* Generate wrap token here. */
00163         }
00164       else if (tok.wrap_length > 0)
00165         {
00166           /* Server provided wrap token but we are not ready for it.
00167              Server error. */
00168           return GSASL_MECHANISM_PARSE_ERROR;
00169         }
00170 
00171       res = gs2_encode (bufdesc2.value, bufdesc2.length,
00172                         NULL, 0, output, output_len);
00173       if (res < 0)
00174         return GSASL_GSSAPI_INIT_SEC_CONTEXT_ERROR;
00175 
00176       if (maj_stat == GSS_S_COMPLETE)
00177         state->step = 2;
00178       else
00179         state->step = 1;
00180 
00181       maj_stat = gss_release_buffer (&min_stat, &bufdesc2);
00182       if (GSS_ERROR (maj_stat))
00183         return GSASL_GSSAPI_RELEASE_BUFFER_ERROR;
00184 
00185       res = GSASL_NEEDS_MORE;
00186       break;
00187 
00188     case 2:
00189       /* [RFC 2222 section 7.2.1]:
00190          The client passes this token to GSS_Unwrap and interprets the
00191          first octet of resulting cleartext as a bit-mask specifying
00192          the security layers supported by the server and the second
00193          through fourth octets as the maximum size output_message to
00194          send to the server.  The client then constructs data, with
00195          the first octet containing the bit-mask specifying the
00196          selected security layer, the second through fourth octets
00197          containing in network byte order the maximum size
00198          output_message the client is able to receive, and the
00199          remaining octets containing the authorization identity.  The
00200          client passes the data to GSS_Wrap with conf_flag set to
00201          FALSE, and responds with the generated output_message.  The
00202          client can then consider the server authenticated. */
00203 
00204       bufdesc.length = input_len;
00205       bufdesc.value = (void *) input;
00206       maj_stat = gss_unwrap (&min_stat, state->context, &bufdesc,
00207                              &bufdesc2, &conf_state, &serverqop);
00208       if (GSS_ERROR (maj_stat))
00209         return GSASL_GSSAPI_UNWRAP_ERROR;
00210 
00211       if (bufdesc2.length != 4)
00212         return GSASL_MECHANISM_PARSE_ERROR;
00213 
00214       memcpy (clientwrap, bufdesc2.value, 4);
00215 
00216       maj_stat = gss_release_buffer (&min_stat, &bufdesc2);
00217       if (GSS_ERROR (maj_stat))
00218         return GSASL_GSSAPI_RELEASE_BUFFER_ERROR;
00219 
00220 #if 0
00221       /* FIXME: Fix qop. */
00222       if (cb_qop)
00223         state->qop = cb_qop (sctx, serverqop);
00224 
00225       if ((state->qop & serverqop) == 0)
00226         /*  Server does not support what user wanted. */
00227         return GSASL_GSSAPI_UNSUPPORTED_PROTECTION_ERROR;
00228 #endif
00229 
00230       /* FIXME: Fix maxbuf. */
00231 
00232       p = gsasl_property_get (sctx, GSASL_AUTHID);
00233       if (!p)
00234         return GSASL_NO_AUTHID;
00235 
00236       bufdesc.length = 4 + strlen (p);
00237       bufdesc.value = malloc (bufdesc.length);
00238       if (!bufdesc.value)
00239         return GSASL_MALLOC_ERROR;
00240 
00241       {
00242         char *q = bufdesc.value;
00243         q[0] = state->qop;
00244         memcpy (q + 1, clientwrap + 1, 3);
00245         memcpy (q + 4, p, strlen (p));
00246       }
00247 
00248       maj_stat = gss_wrap (&min_stat, state->context, 0, GSS_C_QOP_DEFAULT,
00249                            &bufdesc, &conf_state, &bufdesc2);
00250       free (bufdesc.value);
00251       if (GSS_ERROR (maj_stat))
00252         return GSASL_GSSAPI_WRAP_ERROR;
00253 
00254       *output_len = bufdesc2.length;
00255       *output = malloc (bufdesc2.length);
00256       if (!*output)
00257         return GSASL_MALLOC_ERROR;
00258 
00259       memcpy (*output, bufdesc2.value, bufdesc2.length);
00260 
00261       maj_stat = gss_release_buffer (&min_stat, &bufdesc2);
00262       if (GSS_ERROR (maj_stat))
00263         return GSASL_GSSAPI_RELEASE_BUFFER_ERROR;
00264 
00265       state->step++;
00266       res = GSASL_OK;
00267       break;
00268 
00269     default:
00270       res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
00271       break;
00272     }
00273 
00274   return res;
00275 }
00276 
00277 void
00278 _gsasl_gs2_client_finish (Gsasl_session * sctx, void *mech_data)
00279 {
00280   _gsasl_gs2_client_state *state = mech_data;
00281   OM_uint32 maj_stat, min_stat;
00282 
00283   if (!state)
00284     return;
00285 
00286   if (state->service != GSS_C_NO_NAME)
00287     maj_stat = gss_release_name (&min_stat, &state->service);
00288   if (state->context != GSS_C_NO_CONTEXT)
00289     maj_stat = gss_delete_sec_context (&min_stat, &state->context,
00290                                        GSS_C_NO_BUFFER);
00291 
00292   free (state);
00293 }
00294 
00295 int
00296 _gsasl_gs2_client_encode (Gsasl_session * sctx,
00297                           void *mech_data,
00298                           const char *input, size_t input_len,
00299                           char **output, size_t * output_len)
00300 {
00301   _gsasl_gs2_client_state *state = mech_data;
00302   OM_uint32 min_stat, maj_stat;
00303   gss_buffer_desc foo;
00304   gss_buffer_t input_message_buffer = &foo;
00305   gss_buffer_desc output_message_buffer;
00306 
00307   foo.length = input_len;
00308   foo.value = (void *) input;
00309 
00310   if (state && state->step == 3 &&
00311       state->qop & (GSASL_QOP_AUTH_INT | GSASL_QOP_AUTH_CONF))
00312     {
00313       maj_stat = gss_wrap (&min_stat,
00314                            state->context,
00315                            state->qop & GSASL_QOP_AUTH_CONF ? 1 : 0,
00316                            GSS_C_QOP_DEFAULT,
00317                            input_message_buffer,
00318                            NULL, &output_message_buffer);
00319       if (GSS_ERROR (maj_stat))
00320         return GSASL_GSSAPI_WRAP_ERROR;
00321       *output_len = output_message_buffer.length;
00322       *output = malloc (input_len);
00323       if (!*output)
00324         {
00325           maj_stat = gss_release_buffer (&min_stat, &output_message_buffer);
00326           return GSASL_MALLOC_ERROR;
00327         }
00328       memcpy (*output, output_message_buffer.value,
00329               output_message_buffer.length);
00330 
00331       maj_stat = gss_release_buffer (&min_stat, &output_message_buffer);
00332       if (GSS_ERROR (maj_stat))
00333         {
00334           free (*output);
00335           return GSASL_GSSAPI_RELEASE_BUFFER_ERROR;
00336         }
00337     }
00338   else
00339     {
00340       *output_len = input_len;
00341       *output = malloc (input_len);
00342       if (!*output)
00343         return GSASL_MALLOC_ERROR;
00344       memcpy (*output, input, input_len);
00345     }
00346 
00347   return GSASL_OK;
00348 }
00349 
00350 int
00351 _gsasl_gs2_client_decode (Gsasl_session * sctx,
00352                           void *mech_data,
00353                           const char *input, size_t input_len,
00354                           char **output, size_t * output_len)
00355 {
00356   _gsasl_gs2_client_state *state = mech_data;
00357   OM_uint32 min_stat, maj_stat;
00358   gss_buffer_desc foo;
00359   gss_buffer_t input_message_buffer = &foo;
00360   gss_buffer_desc output_message_buffer;
00361 
00362   foo.length = input_len;
00363   foo.value = (void *) input;
00364 
00365   if (state && state->step == 3 &&
00366       state->qop & (GSASL_QOP_AUTH_INT | GSASL_QOP_AUTH_CONF))
00367     {
00368       maj_stat = gss_unwrap (&min_stat,
00369                              state->context,
00370                              input_message_buffer,
00371                              &output_message_buffer, NULL, NULL);
00372       if (GSS_ERROR (maj_stat))
00373         return GSASL_GSSAPI_UNWRAP_ERROR;
00374       *output_len = output_message_buffer.length;
00375       *output = malloc (input_len);
00376       if (!*output)
00377         {
00378           maj_stat = gss_release_buffer (&min_stat, &output_message_buffer);
00379           return GSASL_MALLOC_ERROR;
00380         }
00381       memcpy (*output, output_message_buffer.value,
00382               output_message_buffer.length);
00383 
00384       maj_stat = gss_release_buffer (&min_stat, &output_message_buffer);
00385       if (GSS_ERROR (maj_stat))
00386         {
00387           free (*output);
00388           return GSASL_GSSAPI_RELEASE_BUFFER_ERROR;
00389         }
00390     }
00391   else
00392     {
00393       *output_len = input_len;
00394       *output = malloc (input_len);
00395       if (!*output)
00396         return GSASL_MALLOC_ERROR;
00397       memcpy (*output, input, input_len);
00398     }
00399 
00400   return GSASL_OK;
00401 }

Generated on Tue Oct 21 18:28:18 2008 for gsasl by  doxygen 1.5.6