gsasl  1.8.0
gssapi/client.c
Go to the documentation of this file.
00001 /* client.c --- SASL mechanism GSSAPI as defined in RFC 4752, client side.
00002  * Copyright (C) 2002-2012 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 malloc, free. */
00028 #include <stdlib.h>
00029 
00030 /* Get memcpy, strlen. */
00031 #include <string.h>
00032 
00033 /* Get specification. */
00034 #include "x-gssapi.h"
00035 
00036 #ifdef HAVE_LIBGSS
00037 #include <gss.h>
00038 #elif HAVE_GSSAPI_H
00039 #include <gssapi.h>
00040 #elif HAVE_GSSAPI_GSSAPI_H
00041 #include <gssapi/gssapi.h>
00042 #endif
00043 
00044 #include "gss-extra.h"
00045 
00046 struct _Gsasl_gssapi_client_state
00047 {
00048   int step;
00049   gss_name_t service;
00050   gss_ctx_id_t context;
00051   gss_qop_t qop;
00052 };
00053 typedef struct _Gsasl_gssapi_client_state _Gsasl_gssapi_client_state;
00054 
00055 int
00056 _gsasl_gssapi_client_start (Gsasl_session * sctx, void **mech_data)
00057 {
00058   _Gsasl_gssapi_client_state *state;
00059 
00060   state = (_Gsasl_gssapi_client_state *) malloc (sizeof (*state));
00061   if (state == NULL)
00062     return GSASL_MALLOC_ERROR;
00063 
00064   state->context = GSS_C_NO_CONTEXT;
00065   state->service = GSS_C_NO_NAME;
00066   state->step = 0;
00067   state->qop = GSASL_QOP_AUTH;  /* FIXME: Should be GSASL_QOP_AUTH_CONF. */
00068 
00069   *mech_data = state;
00070 
00071   return GSASL_OK;
00072 }
00073 
00074 int
00075 _gsasl_gssapi_client_step (Gsasl_session * sctx,
00076                            void *mech_data,
00077                            const char *input, size_t input_len,
00078                            char **output, size_t * output_len)
00079 {
00080   _Gsasl_gssapi_client_state *state = mech_data;
00081   char clientwrap[4];
00082   gss_qop_t serverqop;
00083   gss_buffer_desc bufdesc, bufdesc2;
00084   gss_buffer_t buf = GSS_C_NO_BUFFER;
00085   OM_uint32 maj_stat, min_stat;
00086   int conf_state;
00087   int res;
00088   const char *p;
00089 
00090   if (state->service == NULL)
00091     {
00092       const char *service, *hostname;
00093 
00094       service = gsasl_property_get (sctx, GSASL_SERVICE);
00095       if (!service)
00096         return GSASL_NO_SERVICE;
00097 
00098       hostname = gsasl_property_get (sctx, GSASL_HOSTNAME);
00099       if (!hostname)
00100         return GSASL_NO_HOSTNAME;
00101 
00102       /* FIXME: Use asprintf. */
00103 
00104       bufdesc.length = strlen (service) + 1 + strlen (hostname) + 1;
00105       bufdesc.value = malloc (bufdesc.length);
00106       if (bufdesc.value == NULL)
00107         return GSASL_MALLOC_ERROR;
00108 
00109       sprintf (bufdesc.value, "%s@%s", service, hostname);
00110 
00111       maj_stat = gss_import_name (&min_stat, &bufdesc,
00112                                   GSS_C_NT_HOSTBASED_SERVICE,
00113                                   &state->service);
00114       free (bufdesc.value);
00115       if (GSS_ERROR (maj_stat))
00116         return GSASL_GSSAPI_IMPORT_NAME_ERROR;
00117     }
00118 
00119   switch (state->step)
00120     {
00121     case 1:
00122       bufdesc.length = input_len;
00123       bufdesc.value = (void *) input;
00124       buf = &bufdesc;
00125       /* fall through */
00126 
00127     case 0:
00128       bufdesc2.length = 0;
00129       bufdesc2.value = NULL;
00130       maj_stat = gss_init_sec_context (&min_stat,
00131                                        GSS_C_NO_CREDENTIAL,
00132                                        &state->context,
00133                                        state->service,
00134                                        GSS_C_NO_OID,
00135                                        GSS_C_MUTUAL_FLAG |
00136                                        GSS_C_REPLAY_FLAG |
00137                                        GSS_C_SEQUENCE_FLAG |
00138                                        GSS_C_INTEG_FLAG |
00139                                        GSS_C_CONF_FLAG,
00140                                        0,
00141                                        GSS_C_NO_CHANNEL_BINDINGS,
00142                                        buf, NULL, &bufdesc2, NULL, NULL);
00143       if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED)
00144         return GSASL_GSSAPI_INIT_SEC_CONTEXT_ERROR;
00145 
00146       *output_len = bufdesc2.length;
00147       *output = malloc (*output_len);
00148       if (!*output)
00149         return GSASL_MALLOC_ERROR;
00150       memcpy (*output, bufdesc2.value, bufdesc2.length);
00151 
00152       if (maj_stat == GSS_S_COMPLETE)
00153         state->step = 2;
00154       else
00155         state->step = 1;
00156 
00157       maj_stat = gss_release_buffer (&min_stat, &bufdesc2);
00158       if (maj_stat != GSS_S_COMPLETE)
00159         return GSASL_GSSAPI_RELEASE_BUFFER_ERROR;
00160 
00161       res = GSASL_NEEDS_MORE;
00162       break;
00163 
00164     case 2:
00165       /* [RFC 2222 section 7.2.1]:
00166          The client passes this token to GSS_Unwrap and interprets the
00167          first octet of resulting cleartext as a bit-mask specifying
00168          the security layers supported by the server and the second
00169          through fourth octets as the maximum size output_message to
00170          send to the server.  The client then constructs data, with
00171          the first octet containing the bit-mask specifying the
00172          selected security layer, the second through fourth octets
00173          containing in network byte order the maximum size
00174          output_message the client is able to receive, and the
00175          remaining octets containing the authorization identity.  The
00176          client passes the data to GSS_Wrap with conf_flag set to
00177          FALSE, and responds with the generated output_message.  The
00178          client can then consider the server authenticated. */
00179 
00180       bufdesc.length = input_len;
00181       bufdesc.value = (void *) input;
00182       maj_stat = gss_unwrap (&min_stat, state->context, &bufdesc,
00183                              &bufdesc2, &conf_state, &serverqop);
00184       if (GSS_ERROR (maj_stat))
00185         return GSASL_GSSAPI_UNWRAP_ERROR;
00186 
00187       if (bufdesc2.length != 4)
00188         return GSASL_MECHANISM_PARSE_ERROR;
00189 
00190       memcpy (clientwrap, bufdesc2.value, 4);
00191 
00192       maj_stat = gss_release_buffer (&min_stat, &bufdesc2);
00193       if (GSS_ERROR (maj_stat))
00194         return GSASL_GSSAPI_RELEASE_BUFFER_ERROR;
00195 
00196 #if 0
00197       /* FIXME: Fix qop. */
00198       if (cb_qop)
00199         state->qop = cb_qop (sctx, serverqop);
00200 
00201       if ((state->qop & serverqop) == 0)
00202         /*  Server does not support what user wanted. */
00203         return GSASL_GSSAPI_UNSUPPORTED_PROTECTION_ERROR;
00204 #endif
00205 
00206       /* FIXME: Fix maxbuf. */
00207 
00208       p = gsasl_property_get (sctx, GSASL_AUTHID);
00209       if (!p)
00210         return GSASL_NO_AUTHID;
00211 
00212       bufdesc.length = 4 + strlen (p);
00213       bufdesc.value = malloc (bufdesc.length);
00214       if (!bufdesc.value)
00215         return GSASL_MALLOC_ERROR;
00216 
00217       {
00218         char *q = bufdesc.value;
00219         q[0] = state->qop;
00220         memcpy (q + 1, clientwrap + 1, 3);
00221         memcpy (q + 4, p, strlen (p));
00222       }
00223 
00224       maj_stat = gss_wrap (&min_stat, state->context, 0, GSS_C_QOP_DEFAULT,
00225                            &bufdesc, &conf_state, &bufdesc2);
00226       free (bufdesc.value);
00227       if (GSS_ERROR (maj_stat))
00228         return GSASL_GSSAPI_WRAP_ERROR;
00229 
00230       *output_len = bufdesc2.length;
00231       *output = malloc (bufdesc2.length);
00232       if (!*output)
00233         return GSASL_MALLOC_ERROR;
00234 
00235       memcpy (*output, bufdesc2.value, bufdesc2.length);
00236 
00237       maj_stat = gss_release_buffer (&min_stat, &bufdesc2);
00238       if (GSS_ERROR (maj_stat))
00239         return GSASL_GSSAPI_RELEASE_BUFFER_ERROR;
00240 
00241       state->step++;
00242       res = GSASL_OK;
00243       break;
00244 
00245     default:
00246       res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
00247       break;
00248     }
00249 
00250   return res;
00251 }
00252 
00253 void
00254 _gsasl_gssapi_client_finish (Gsasl_session * sctx, void *mech_data)
00255 {
00256   _Gsasl_gssapi_client_state *state = mech_data;
00257   OM_uint32 maj_stat, min_stat;
00258 
00259   if (!state)
00260     return;
00261 
00262   if (state->service != GSS_C_NO_NAME)
00263     maj_stat = gss_release_name (&min_stat, &state->service);
00264   if (state->context != GSS_C_NO_CONTEXT)
00265     maj_stat = gss_delete_sec_context (&min_stat, &state->context,
00266                                        GSS_C_NO_BUFFER);
00267 
00268   free (state);
00269 }
00270 
00271 int
00272 _gsasl_gssapi_client_encode (Gsasl_session * sctx,
00273                              void *mech_data,
00274                              const char *input, size_t input_len,
00275                              char **output, size_t * output_len)
00276 {
00277   _Gsasl_gssapi_client_state *state = mech_data;
00278   OM_uint32 min_stat, maj_stat;
00279   gss_buffer_desc foo;
00280   gss_buffer_t input_message_buffer = &foo;
00281   gss_buffer_desc output_message_buffer;
00282 
00283   foo.length = input_len;
00284   foo.value = (void *) input;
00285 
00286   if (state && state->step == 3 &&
00287       state->qop & (GSASL_QOP_AUTH_INT | GSASL_QOP_AUTH_CONF))
00288     {
00289       maj_stat = gss_wrap (&min_stat,
00290                            state->context,
00291                            state->qop & GSASL_QOP_AUTH_CONF ? 1 : 0,
00292                            GSS_C_QOP_DEFAULT,
00293                            input_message_buffer,
00294                            NULL, &output_message_buffer);
00295       if (GSS_ERROR (maj_stat))
00296         return GSASL_GSSAPI_WRAP_ERROR;
00297       *output_len = output_message_buffer.length;
00298       *output = malloc (input_len);
00299       if (!*output)
00300         {
00301           maj_stat = gss_release_buffer (&min_stat, &output_message_buffer);
00302           return GSASL_MALLOC_ERROR;
00303         }
00304       memcpy (*output, output_message_buffer.value,
00305               output_message_buffer.length);
00306 
00307       maj_stat = gss_release_buffer (&min_stat, &output_message_buffer);
00308       if (GSS_ERROR (maj_stat))
00309         {
00310           free (*output);
00311           return GSASL_GSSAPI_RELEASE_BUFFER_ERROR;
00312         }
00313     }
00314   else
00315     {
00316       *output_len = input_len;
00317       *output = malloc (input_len);
00318       if (!*output)
00319         return GSASL_MALLOC_ERROR;
00320       memcpy (*output, input, input_len);
00321     }
00322 
00323   return GSASL_OK;
00324 }
00325 
00326 int
00327 _gsasl_gssapi_client_decode (Gsasl_session * sctx,
00328                              void *mech_data,
00329                              const char *input, size_t input_len,
00330                              char **output, size_t * output_len)
00331 {
00332   _Gsasl_gssapi_client_state *state = mech_data;
00333   OM_uint32 min_stat, maj_stat;
00334   gss_buffer_desc foo;
00335   gss_buffer_t input_message_buffer = &foo;
00336   gss_buffer_desc output_message_buffer;
00337 
00338   foo.length = input_len;
00339   foo.value = (void *) input;
00340 
00341   if (state && state->step == 3 &&
00342       state->qop & (GSASL_QOP_AUTH_INT | GSASL_QOP_AUTH_CONF))
00343     {
00344       maj_stat = gss_unwrap (&min_stat,
00345                              state->context,
00346                              input_message_buffer,
00347                              &output_message_buffer, NULL, NULL);
00348       if (GSS_ERROR (maj_stat))
00349         return GSASL_GSSAPI_UNWRAP_ERROR;
00350       *output_len = output_message_buffer.length;
00351       *output = malloc (input_len);
00352       if (!*output)
00353         {
00354           maj_stat = gss_release_buffer (&min_stat, &output_message_buffer);
00355           return GSASL_MALLOC_ERROR;
00356         }
00357       memcpy (*output, output_message_buffer.value,
00358               output_message_buffer.length);
00359 
00360       maj_stat = gss_release_buffer (&min_stat, &output_message_buffer);
00361       if (GSS_ERROR (maj_stat))
00362         {
00363           free (*output);
00364           return GSASL_GSSAPI_RELEASE_BUFFER_ERROR;
00365         }
00366     }
00367   else
00368     {
00369       *output_len = input_len;
00370       *output = malloc (input_len);
00371       if (!*output)
00372         return GSASL_MALLOC_ERROR;
00373       memcpy (*output, input, input_len);
00374     }
00375 
00376   return GSASL_OK;
00377 }