gsasl  1.8.0
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-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_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       if (maj_stat == GSS_S_COMPLETE)
00166         state->step++;
00167 
00168       if (maj_stat == GSS_S_CONTINUE_NEEDED || bufdesc2.length > 0)
00169         {
00170           *output = malloc (bufdesc2.length);
00171           if (!*output)
00172             return GSASL_MALLOC_ERROR;
00173           memcpy (*output, bufdesc2.value, bufdesc2.length);
00174           *output_len = bufdesc2.length;
00175         }
00176 
00177       maj_stat = gss_release_buffer (&min_stat, &bufdesc2);
00178       if (GSS_ERROR (maj_stat))
00179         return GSASL_GSSAPI_RELEASE_BUFFER_ERROR;
00180 
00181       if (maj_stat == GSS_S_CONTINUE_NEEDED || *output_len > 0)
00182         {
00183           res = GSASL_NEEDS_MORE;
00184           break;
00185         }
00186       /* fall through */
00187 
00188     case 2:
00189       memset (tmp, 0xFF, 4);
00190       tmp[0] = GSASL_QOP_AUTH;
00191       bufdesc1.length = 4;
00192       bufdesc1.value = tmp;
00193       maj_stat = gss_wrap (&min_stat, state->context, 0, GSS_C_QOP_DEFAULT,
00194                            &bufdesc1, NULL, &bufdesc2);
00195       if (GSS_ERROR (maj_stat))
00196         return GSASL_GSSAPI_WRAP_ERROR;
00197 
00198       *output = malloc (bufdesc2.length);
00199       if (!*output)
00200         return GSASL_MALLOC_ERROR;
00201       memcpy (*output, bufdesc2.value, bufdesc2.length);
00202       *output_len = bufdesc2.length;
00203 
00204       maj_stat = gss_release_buffer (&min_stat, &bufdesc2);
00205       if (GSS_ERROR (maj_stat))
00206         return GSASL_GSSAPI_RELEASE_BUFFER_ERROR;
00207 
00208       state->step++;
00209       res = GSASL_NEEDS_MORE;
00210       break;
00211 
00212     case 3:
00213       bufdesc1.value = (void *) input;
00214       bufdesc1.length = input_len;
00215       maj_stat = gss_unwrap (&min_stat, state->context, &bufdesc1,
00216                              &bufdesc2, NULL, NULL);
00217       if (GSS_ERROR (maj_stat))
00218         return GSASL_GSSAPI_UNWRAP_ERROR;
00219 
00220       /* [RFC 2222 section 7.2.1]:
00221          The client passes this token to GSS_Unwrap and interprets the
00222          first octet of resulting cleartext as a bit-mask specifying
00223          the security layers supported by the server and the second
00224          through fourth octets as the maximum size output_message to
00225          send to the server.  The client then constructs data, with
00226          the first octet containing the bit-mask specifying the
00227          selected security layer, the second through fourth octets
00228          containing in network byte order the maximum size
00229          output_message the client is able to receive, and the
00230          remaining octets containing the authorization identity.  The
00231          client passes the data to GSS_Wrap with conf_flag set to
00232          FALSE, and responds with the generated output_message.  The
00233          client can then consider the server authenticated. */
00234 
00235       if ((((char *) bufdesc2.value)[0] & GSASL_QOP_AUTH) == 0)
00236         {
00237           /* Integrity or privacy unsupported */
00238           maj_stat = gss_release_buffer (&min_stat, &bufdesc2);
00239           return GSASL_GSSAPI_UNSUPPORTED_PROTECTION_ERROR;
00240         }
00241 
00242       gsasl_property_set_raw (sctx, GSASL_AUTHZID,
00243                               (char *) bufdesc2.value + 4,
00244                               bufdesc2.length - 4);
00245 
00246       maj_stat = gss_display_name (&min_stat, state->client,
00247                                    &client_name, &mech_type);
00248       if (GSS_ERROR (maj_stat))
00249         return GSASL_GSSAPI_DISPLAY_NAME_ERROR;
00250 
00251       gsasl_property_set_raw (sctx, GSASL_GSSAPI_DISPLAY_NAME,
00252                               client_name.value, client_name.length);
00253 
00254       maj_stat = gss_release_buffer (&min_stat, &bufdesc2);
00255       if (GSS_ERROR (maj_stat))
00256         return GSASL_GSSAPI_RELEASE_BUFFER_ERROR;
00257 
00258       res = gsasl_callback (NULL, sctx, GSASL_VALIDATE_GSSAPI);
00259 
00260       state->step++;
00261       break;
00262 
00263     default:
00264       res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
00265       break;
00266     }
00267 
00268   return res;
00269 }
00270 
00271 void
00272 _gsasl_gssapi_server_finish (Gsasl_session * sctx, void *mech_data)
00273 {
00274   _Gsasl_gssapi_server_state *state = mech_data;
00275   OM_uint32 min_stat;
00276 
00277   if (!state)
00278     return;
00279 
00280   if (state->context != GSS_C_NO_CONTEXT)
00281     gss_delete_sec_context (&min_stat, &state->context, GSS_C_NO_BUFFER);
00282 
00283   if (state->cred != GSS_C_NO_CREDENTIAL)
00284     gss_release_cred (&min_stat, &state->cred);
00285 
00286   if (state->client != GSS_C_NO_NAME)
00287     gss_release_name (&min_stat, &state->client);
00288 
00289   free (state);
00290 }