gsasl  1.8.0
gs2/server.c
Go to the documentation of this file.
00001 /* server.c --- SASL mechanism GS2, 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 specification. */
00028 #include "gs2.h"
00029 
00030 /* Get malloc, free. */
00031 #include <stdlib.h>
00032 
00033 /* Get memcpy, strlen. */
00034 #include <string.h>
00035 
00036 #include "gss-extra.h"
00037 #include "gs2helper.h"
00038 #include "mechtools.h"
00039 
00040 struct _Gsasl_gs2_server_state
00041 {
00042   /* steps: 0 = first state, 1 = initial, 2 = processing, 3 = done */
00043   int step;
00044   gss_name_t client;
00045   gss_cred_id_t cred;
00046   gss_ctx_id_t context;
00047   gss_OID mech_oid;
00048   struct gss_channel_bindings_struct cb;
00049 };
00050 typedef struct _Gsasl_gs2_server_state _Gsasl_gs2_server_state;
00051 
00052 /* Populate state->cred with credential to use for connection.  Return
00053    GSASL_OK on success or an error code.  */
00054 static int
00055 gs2_get_cred (Gsasl_session * sctx, _Gsasl_gs2_server_state * state)
00056 {
00057   OM_uint32 maj_stat, min_stat;
00058   gss_buffer_desc bufdesc;
00059   const char *service = gsasl_property_get (sctx, GSASL_SERVICE);
00060   const char *hostname = gsasl_property_get (sctx, GSASL_HOSTNAME);
00061   gss_name_t server;
00062   gss_OID_set_desc oid_set;
00063   gss_OID_set actual_mechs;
00064   int present;
00065 
00066   if (!service)
00067     return GSASL_NO_SERVICE;
00068   if (!hostname)
00069     return GSASL_NO_HOSTNAME;
00070 
00071   bufdesc.length = asprintf ((char **) &bufdesc.value, "%s@%s",
00072                              service, hostname);
00073   if (bufdesc.length <= 0 || bufdesc.value == NULL)
00074     return GSASL_MALLOC_ERROR;
00075 
00076   maj_stat = gss_import_name (&min_stat, &bufdesc,
00077                               GSS_C_NT_HOSTBASED_SERVICE, &server);
00078   free (bufdesc.value);
00079   if (GSS_ERROR (maj_stat))
00080     return GSASL_GSSAPI_IMPORT_NAME_ERROR;
00081 
00082   /* Attempt to get a credential for our mechanism.  */
00083 
00084   oid_set.count = 1;
00085   oid_set.elements = state->mech_oid;
00086 
00087   maj_stat = gss_acquire_cred (&min_stat, server, 0,
00088                                &oid_set, GSS_C_ACCEPT,
00089                                &state->cred, &actual_mechs, NULL);
00090   gss_release_name (&min_stat, &server);
00091   if (GSS_ERROR (maj_stat))
00092     return GSASL_GSSAPI_ACQUIRE_CRED_ERROR;
00093 
00094   /* Now double check that the credential actually was for our
00095      mechanism... */
00096 
00097   maj_stat = gss_test_oid_set_member (&min_stat, state->mech_oid,
00098                                       actual_mechs, &present);
00099   if (GSS_ERROR (maj_stat))
00100     {
00101       gss_release_oid_set (&min_stat, &actual_mechs);
00102       return GSASL_GSSAPI_TEST_OID_SET_MEMBER_ERROR;
00103     }
00104 
00105   maj_stat = gss_release_oid_set (&min_stat, &actual_mechs);
00106   if (GSS_ERROR (maj_stat))
00107     return GSASL_GSSAPI_RELEASE_OID_SET_ERROR;
00108 
00109   if (!present)
00110     return GSASL_GSSAPI_ACQUIRE_CRED_ERROR;
00111 
00112   return GSASL_OK;
00113 }
00114 
00115 /* Initialize GS2 state into MECH_DATA.  Return GSASL_OK if GS2 is
00116    ready and initialization succeeded, or an error code. */
00117 int
00118 _gsasl_gs2_server_start (Gsasl_session * sctx, void **mech_data)
00119 {
00120   _Gsasl_gs2_server_state *state;
00121   int res;
00122 
00123   state = (_Gsasl_gs2_server_state *) malloc (sizeof (*state));
00124   if (state == NULL)
00125     return GSASL_MALLOC_ERROR;
00126 
00127   res = gs2_get_oid (sctx, &state->mech_oid);
00128   if (res != GSASL_OK)
00129     {
00130       free (state);
00131       return res;
00132     }
00133 
00134   res = gs2_get_cred (sctx, state);
00135   if (res != GSASL_OK)
00136     {
00137       free (state);
00138       return res;
00139     }
00140 
00141   state->step = 0;
00142   state->context = GSS_C_NO_CONTEXT;
00143   state->client = NULL;
00144   /* The initiator-address-type and acceptor-address-type fields of
00145      the GSS-CHANNEL-BINDINGS structure MUST be set to 0.  The
00146      initiator-address and acceptor-address fields MUST be the empty
00147      string. */
00148   state->cb.initiator_addrtype = 0;
00149   state->cb.initiator_address.length = 0;
00150   state->cb.initiator_address.value = NULL;
00151   state->cb.acceptor_addrtype = 0;
00152   state->cb.acceptor_address.length = 0;
00153   state->cb.acceptor_address.value = NULL;
00154   state->cb.application_data.length = 0;
00155   state->cb.application_data.value = NULL;
00156 
00157   *mech_data = state;
00158 
00159   return GSASL_OK;
00160 }
00161 
00162 /* Perform one GS2 step.  GS2 state is in MECH_DATA.  Any data from
00163    client is provided in INPUT/INPUT_LEN and output from server is
00164    expected to be put in newly allocated OUTPUT/OUTPUT_LEN.  Return
00165    GSASL_NEEDS_MORE or GSASL_OK on success, or an error code.  */
00166 int
00167 _gsasl_gs2_server_step (Gsasl_session * sctx,
00168                         void *mech_data,
00169                         const char *input, size_t input_len,
00170                         char **output, size_t * output_len)
00171 {
00172   _Gsasl_gs2_server_state *state = mech_data;
00173   gss_buffer_desc bufdesc1, bufdesc2;
00174   OM_uint32 maj_stat, min_stat;
00175   gss_buffer_desc client_name;
00176   gss_OID mech_type;
00177   int res;
00178   OM_uint32 ret_flags;
00179   int free_bufdesc1 = 0;
00180 
00181   *output = NULL;
00182   *output_len = 0;
00183   bufdesc1.value = input;
00184   bufdesc1.length = input_len;
00185 
00186   switch (state->step)
00187     {
00188     case 0:
00189       if (input_len == 0)
00190         {
00191           res = GSASL_NEEDS_MORE;
00192           break;
00193         }
00194       state->step++;
00195       /* fall through */
00196 
00197     case 1:
00198       {
00199         char *authzid;
00200         size_t headerlen;
00201 
00202         res = _gsasl_parse_gs2_header (input, input_len,
00203                                        &authzid, &headerlen);
00204         if (res != GSASL_OK)
00205           return res;
00206 
00207         if (authzid)
00208           {
00209             gsasl_property_set (sctx, GSASL_AUTHZID, authzid);
00210             free (authzid);
00211           }
00212 
00213         state->cb.application_data.value = input;
00214         state->cb.application_data.length = headerlen;
00215 
00216         bufdesc2.value = input + headerlen;
00217         bufdesc2.length = input_len - headerlen;
00218 
00219         maj_stat = gss_encapsulate_token (&bufdesc2, state->mech_oid,
00220                                           &bufdesc1);
00221         if (GSS_ERROR (maj_stat))
00222           return GSASL_GSSAPI_ENCAPSULATE_TOKEN_ERROR;
00223 
00224         free_bufdesc1 = 1;
00225       }
00226       state->step++;
00227       /* fall through */
00228 
00229     case 2:
00230       if (state->client)
00231         {
00232           gss_release_name (&min_stat, &state->client);
00233           state->client = GSS_C_NO_NAME;
00234         }
00235 
00236       maj_stat = gss_accept_sec_context (&min_stat,
00237                                          &state->context,
00238                                          state->cred,
00239                                          &bufdesc1,
00240                                          &state->cb,
00241                                          &state->client,
00242                                          &mech_type,
00243                                          &bufdesc2, &ret_flags, NULL, NULL);
00244       if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED)
00245         return GSASL_GSSAPI_ACCEPT_SEC_CONTEXT_ERROR;
00246 
00247       if (maj_stat == GSS_S_COMPLETE)
00248         {
00249           state->step++;
00250 
00251           if (!(ret_flags & GSS_C_MUTUAL_FLAG))
00252             return GSASL_MECHANISM_PARSE_ERROR;
00253 
00254           maj_stat = gss_display_name (&min_stat, state->client,
00255                                        &client_name, &mech_type);
00256           if (GSS_ERROR (maj_stat))
00257             return GSASL_GSSAPI_DISPLAY_NAME_ERROR;
00258 
00259           gsasl_property_set_raw (sctx, GSASL_GSSAPI_DISPLAY_NAME,
00260                                   client_name.value, client_name.length);
00261 
00262           res = gsasl_callback (NULL, sctx, GSASL_VALIDATE_GSSAPI);
00263         }
00264       else
00265         res = GSASL_NEEDS_MORE;
00266 
00267       if (free_bufdesc1)
00268         {
00269           maj_stat = gss_release_buffer (&min_stat, &bufdesc1);
00270           if (GSS_ERROR (maj_stat))
00271             return GSASL_GSSAPI_RELEASE_BUFFER_ERROR;
00272         }
00273 
00274       *output = malloc (bufdesc2.length);
00275       if (!*output)
00276         return GSASL_MALLOC_ERROR;
00277       memcpy (*output, bufdesc2.value, bufdesc2.length);
00278       *output_len = bufdesc2.length;
00279 
00280       maj_stat = gss_release_buffer (&min_stat, &bufdesc2);
00281       if (GSS_ERROR (maj_stat))
00282         return GSASL_GSSAPI_RELEASE_BUFFER_ERROR;
00283       break;
00284 
00285     default:
00286       res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
00287       break;
00288     }
00289 
00290   return res;
00291 }
00292 
00293 /* Cleanup GS2 state context, i.e., release memory associated with
00294    buffers in MECH_DATA state. */
00295 void
00296 _gsasl_gs2_server_finish (Gsasl_session * sctx, void *mech_data)
00297 {
00298   _Gsasl_gs2_server_state *state = mech_data;
00299   OM_uint32 min_stat;
00300 
00301   if (!state)
00302     return;
00303 
00304   if (state->context != GSS_C_NO_CONTEXT)
00305     gss_delete_sec_context (&min_stat, &state->context, GSS_C_NO_BUFFER);
00306 
00307   if (state->cred != GSS_C_NO_CREDENTIAL)
00308     gss_release_cred (&min_stat, &state->cred);
00309 
00310   if (state->client != GSS_C_NO_NAME)
00311     gss_release_name (&min_stat, &state->client);
00312 
00313   free (state);
00314 }