gssapi/client.c

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

Generated on Tue Aug 22 12:06:06 2006 for gsasl by  doxygen 1.4.7