gssapi/server.c

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