00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #if HAVE_CONFIG_H
00024 # include "config.h"
00025 #endif
00026
00027
00028 #include <stdlib.h>
00029
00030
00031 #include <string.h>
00032
00033
00034 #include "x-gssapi.h"
00035
00036 #ifdef USE_GSS
00037 # include <gss.h>
00038 #elif HAVE_GSSAPI_H
00039 # include <gssapi.h>
00040 #else
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
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
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
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231 if ((((char *) bufdesc2.value)[0] & GSASL_QOP_AUTH) == 0)
00232 {
00233
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 }