gssapi/server.c

Go to the documentation of this file.
00001 /* server.c --- SASL mechanism GSSAPI as defined in RFC 2222, server 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_server_state
00050 {
00051   int step;
00052   gss_name_t client;
00053   gss_cred_id_t cred;
00054   gss_ctx_id_t context;
00055 };
00056 typedef struct _Gsasl_gssapi_server_state _Gsasl_gssapi_server_state;
00057 
00058 int
00059 _gsasl_gssapi_server_start (Gsasl_session * sctx, void **mech_data)
00060 {
00061   _Gsasl_gssapi_server_state *state;
00062   OM_uint32 maj_stat, min_stat;
00063   gss_name_t server;
00064   gss_buffer_desc bufdesc;
00065   const char *service;
00066   const char *hostname;
00067 
00068   service = gsasl_property_get (sctx, GSASL_SERVICE);
00069   if (!service)
00070     return GSASL_NO_SERVICE;
00071 
00072   hostname = gsasl_property_get (sctx, GSASL_HOSTNAME);
00073   if (!hostname)
00074     return GSASL_NO_HOSTNAME;
00075 
00076   /* FIXME: Use asprintf. */
00077 
00078   bufdesc.length = strlen (service) + strlen ("@") + strlen (hostname) + 1;
00079   bufdesc.value = malloc (bufdesc.length);
00080   if (bufdesc.value == NULL)
00081     return GSASL_MALLOC_ERROR;
00082 
00083   sprintf (bufdesc.value, "%s@%s", service, hostname);
00084 
00085   state = (_Gsasl_gssapi_server_state *) malloc (sizeof (*state));
00086   if (state == NULL)
00087     {
00088       free (bufdesc.value);
00089       return GSASL_MALLOC_ERROR;
00090     }
00091 
00092   maj_stat = gss_import_name (&min_stat, &bufdesc, GSS_C_NT_HOSTBASED_SERVICE,
00093                               &server);
00094   free (bufdesc.value);
00095   if (GSS_ERROR (maj_stat))
00096     {
00097       free (state);
00098       return GSASL_GSSAPI_IMPORT_NAME_ERROR;
00099     }
00100 
00101   maj_stat = gss_acquire_cred (&min_stat, server, 0,
00102                                GSS_C_NULL_OID_SET, GSS_C_ACCEPT,
00103                                &state->cred, NULL, NULL);
00104   gss_release_name (&min_stat, &server);
00105 
00106   if (GSS_ERROR (maj_stat))
00107     {
00108       free (state);
00109       return GSASL_GSSAPI_ACQUIRE_CRED_ERROR;
00110     }
00111 
00112   state->step = 0;
00113   state->context = GSS_C_NO_CONTEXT;
00114   state->client = NULL;
00115   *mech_data = state;
00116 
00117   return GSASL_OK;
00118 }
00119 
00120 int
00121 _gsasl_gssapi_server_step (Gsasl_session * sctx,
00122                            void *mech_data,
00123                            const char *input, size_t input_len,
00124                            char **output, size_t * output_len)
00125 {
00126   _Gsasl_gssapi_server_state *state = mech_data;
00127   gss_buffer_desc bufdesc1, bufdesc2;
00128   OM_uint32 maj_stat, min_stat;
00129   gss_buffer_desc client_name;
00130   gss_OID mech_type;
00131   char tmp[4];
00132   int res;
00133 
00134   *output = NULL;
00135   *output_len = 0;
00136 
00137   switch (state->step)
00138     {
00139     case 0:
00140       if (input_len == 0)
00141         {
00142           res = GSASL_NEEDS_MORE;
00143           break;
00144         }
00145       state->step++;
00146       /* fall through */
00147 
00148     case 1:
00149       bufdesc1.value = (void *) input;
00150       bufdesc1.length = input_len;
00151       if (state->client)
00152         {
00153           gss_release_name (&min_stat, &state->client);
00154           state->client = GSS_C_NO_NAME;
00155         }
00156 
00157       maj_stat = gss_accept_sec_context (&min_stat,
00158                                          &state->context,
00159                                          state->cred,
00160                                          &bufdesc1,
00161                                          GSS_C_NO_CHANNEL_BINDINGS,
00162                                          &state->client,
00163                                          &mech_type,
00164                                          &bufdesc2, NULL, NULL, NULL);
00165       if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED)
00166         return GSASL_GSSAPI_ACCEPT_SEC_CONTEXT_ERROR;
00167 
00168       *output = malloc (bufdesc2.length);
00169       if (!*output)
00170         return GSASL_MALLOC_ERROR;
00171       memcpy (*output, bufdesc2.value, bufdesc2.length);
00172       *output_len = bufdesc2.length;
00173 
00174       maj_stat = gss_release_buffer (&min_stat, &bufdesc2);
00175       if (GSS_ERROR (maj_stat))
00176         return GSASL_GSSAPI_RELEASE_BUFFER_ERROR;
00177 
00178       if (maj_stat == GSS_S_COMPLETE)
00179         state->step++;
00180 
00181       res = GSASL_NEEDS_MORE;
00182       break;
00183 
00184     case 2:
00185       memset (tmp, 0xFF, 4);
00186       tmp[0] = GSASL_QOP_AUTH;
00187       bufdesc1.length = 4;
00188       bufdesc1.value = tmp;
00189       maj_stat = gss_wrap (&min_stat, state->context, 0, GSS_C_QOP_DEFAULT,
00190                            &bufdesc1, NULL, &bufdesc2);
00191       if (GSS_ERROR (maj_stat))
00192         return GSASL_GSSAPI_WRAP_ERROR;
00193 
00194       *output = malloc (bufdesc2.length);
00195       if (!*output)
00196         return GSASL_MALLOC_ERROR;
00197       memcpy (*output, bufdesc2.value, bufdesc2.length);
00198       *output_len = bufdesc2.length;
00199 
00200       maj_stat = gss_release_buffer (&min_stat, &bufdesc2);
00201       if (GSS_ERROR (maj_stat))
00202         return GSASL_GSSAPI_RELEASE_BUFFER_ERROR;
00203 
00204       state->step++;
00205       res = GSASL_NEEDS_MORE;
00206       break;
00207 
00208     case 3:
00209       bufdesc1.value = (void *) input;
00210       bufdesc1.length = input_len;
00211       maj_stat = gss_unwrap (&min_stat, state->context, &bufdesc1,
00212                              &bufdesc2, NULL, NULL);
00213       if (GSS_ERROR (maj_stat))
00214         return GSASL_GSSAPI_UNWRAP_ERROR;
00215 
00216       /* [RFC 2222 section 7.2.1]:
00217          The client passes this token to GSS_Unwrap and interprets the
00218          first octet of resulting cleartext as a bit-mask specifying
00219          the security layers supported by the server and the second
00220          through fourth octets as the maximum size output_message to
00221          send to the server.  The client then constructs data, with
00222          the first octet containing the bit-mask specifying the
00223          selected security layer, the second through fourth octets
00224          containing in network byte order the maximum size
00225          output_message the client is able to receive, and the
00226          remaining octets containing the authorization identity.  The
00227          client passes the data to GSS_Wrap with conf_flag set to
00228          FALSE, and responds with the generated output_message.  The
00229          client can then consider the server authenticated. */
00230 
00231       if ((((char *) bufdesc2.value)[0] & GSASL_QOP_AUTH) == 0)
00232         {
00233           /* Integrity or privacy unsupported */
00234           maj_stat = gss_release_buffer (&min_stat, &bufdesc2);
00235           return GSASL_GSSAPI_UNSUPPORTED_PROTECTION_ERROR;
00236         }
00237 
00238       gsasl_property_set_raw (sctx, GSASL_AUTHZID,
00239                               (char*)bufdesc2.value + 4, bufdesc2.length - 4);
00240 
00241       maj_stat = gss_display_name (&min_stat, state->client,
00242                                    &client_name, &mech_type);
00243       if (GSS_ERROR (maj_stat))
00244         return GSASL_GSSAPI_DISPLAY_NAME_ERROR;
00245 
00246       gsasl_property_set_raw (sctx, GSASL_GSSAPI_DISPLAY_NAME,
00247                               client_name.value, client_name.length);
00248 
00249       maj_stat = gss_release_buffer (&min_stat, &bufdesc2);
00250       if (GSS_ERROR (maj_stat))
00251         return GSASL_GSSAPI_RELEASE_BUFFER_ERROR;
00252 
00253       res = gsasl_callback (NULL, sctx, GSASL_VALIDATE_GSSAPI);
00254 
00255       state->step++;
00256       break;
00257 
00258     default:
00259       res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
00260       break;
00261     }
00262 
00263   return res;
00264 }
00265 
00266 void
00267 _gsasl_gssapi_server_finish (Gsasl_session * sctx, void *mech_data)
00268 {
00269   _Gsasl_gssapi_server_state *state = mech_data;
00270   OM_uint32 min_stat;
00271 
00272   if (!state)
00273     return;
00274 
00275   if (state->context != GSS_C_NO_CONTEXT)
00276     gss_delete_sec_context (&min_stat, &state->context, GSS_C_NO_BUFFER);
00277 
00278   if (state->cred != GSS_C_NO_CREDENTIAL)
00279     gss_release_cred (&min_stat, &state->cred);
00280 
00281   if (state->client != GSS_C_NO_NAME)
00282     gss_release_name (&min_stat, &state->client);
00283 
00284   free (state);
00285 }

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