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_client_state
00050 {
00051 int step;
00052 gss_name_t service;
00053 gss_ctx_id_t context;
00054 gss_qop_t qop;
00055 };
00056 typedef struct _Gsasl_gssapi_client_state _Gsasl_gssapi_client_state;
00057
00058 int
00059 _gsasl_gssapi_client_start (Gsasl_session * sctx, void **mech_data)
00060 {
00061 _Gsasl_gssapi_client_state *state;
00062
00063 state = (_Gsasl_gssapi_client_state *) malloc (sizeof (*state));
00064 if (state == NULL)
00065 return GSASL_MALLOC_ERROR;
00066
00067 state->context = GSS_C_NO_CONTEXT;
00068 state->service = GSS_C_NO_NAME;
00069 state->step = 0;
00070 state->qop = GSASL_QOP_AUTH;
00071
00072 *mech_data = state;
00073
00074 return GSASL_OK;
00075 }
00076
00077 int
00078 _gsasl_gssapi_client_step (Gsasl_session * sctx,
00079 void *mech_data,
00080 const char *input, size_t input_len,
00081 char **output, size_t * output_len)
00082 {
00083 _Gsasl_gssapi_client_state *state = mech_data;
00084 char clientwrap[4];
00085 gss_qop_t serverqop;
00086 gss_buffer_desc bufdesc, bufdesc2;
00087 gss_buffer_t buf = GSS_C_NO_BUFFER;
00088 OM_uint32 maj_stat, min_stat;
00089 int conf_state;
00090 int res;
00091 const char *p;
00092
00093 if (state->service == NULL)
00094 {
00095 const char *service, *hostname;
00096
00097 service = gsasl_property_get (sctx, GSASL_SERVICE);
00098 if (!service)
00099 return GSASL_NO_SERVICE;
00100
00101 hostname = gsasl_property_get (sctx, GSASL_HOSTNAME);
00102 if (!hostname)
00103 return GSASL_NO_HOSTNAME;
00104
00105
00106
00107 bufdesc.length = strlen (service) + 1 + strlen (hostname) + 1;
00108 bufdesc.value = malloc (bufdesc.length);
00109 if (bufdesc.value == NULL)
00110 return GSASL_MALLOC_ERROR;
00111
00112 sprintf (bufdesc.value, "%s@%s", service, hostname);
00113
00114 maj_stat = gss_import_name (&min_stat, &bufdesc,
00115 GSS_C_NT_HOSTBASED_SERVICE,
00116 &state->service);
00117 free (bufdesc.value);
00118 if (GSS_ERROR (maj_stat))
00119 return GSASL_GSSAPI_IMPORT_NAME_ERROR;
00120 }
00121
00122 switch (state->step)
00123 {
00124 case 1:
00125 bufdesc.length = input_len;
00126 bufdesc.value = (void *) input;
00127 buf = &bufdesc;
00128
00129
00130 case 0:
00131 bufdesc2.length = 0;
00132 bufdesc2.value = NULL;
00133 maj_stat = gss_init_sec_context (&min_stat,
00134 GSS_C_NO_CREDENTIAL,
00135 &state->context,
00136 state->service,
00137 GSS_C_NO_OID,
00138 GSS_C_MUTUAL_FLAG |
00139 GSS_C_REPLAY_FLAG |
00140 GSS_C_SEQUENCE_FLAG |
00141 GSS_C_INTEG_FLAG |
00142 GSS_C_CONF_FLAG,
00143 0,
00144 GSS_C_NO_CHANNEL_BINDINGS,
00145 buf, NULL, &bufdesc2, NULL, NULL);
00146 if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED)
00147 return GSASL_GSSAPI_INIT_SEC_CONTEXT_ERROR;
00148
00149 *output_len = bufdesc2.length;
00150 *output = malloc (*output_len);
00151 if (!*output)
00152 return GSASL_MALLOC_ERROR;
00153 memcpy (*output, bufdesc2.value, bufdesc2.length);
00154
00155 if (maj_stat == GSS_S_COMPLETE)
00156 state->step = 2;
00157 else
00158 state->step = 1;
00159
00160 maj_stat = gss_release_buffer (&min_stat, &bufdesc2);
00161 if (maj_stat != GSS_S_COMPLETE)
00162 return GSASL_GSSAPI_RELEASE_BUFFER_ERROR;
00163
00164 res = GSASL_NEEDS_MORE;
00165 break;
00166
00167 case 2:
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183 bufdesc.length = input_len;
00184 bufdesc.value = (void *) input;
00185 maj_stat = gss_unwrap (&min_stat, state->context, &bufdesc,
00186 &bufdesc2, &conf_state, &serverqop);
00187 if (GSS_ERROR (maj_stat))
00188 return GSASL_GSSAPI_UNWRAP_ERROR;
00189
00190 if (bufdesc2.length != 4)
00191 return GSASL_MECHANISM_PARSE_ERROR;
00192
00193 memcpy (clientwrap, bufdesc2.value, 4);
00194
00195 maj_stat = gss_release_buffer (&min_stat, &bufdesc2);
00196 if (GSS_ERROR (maj_stat))
00197 return GSASL_GSSAPI_RELEASE_BUFFER_ERROR;
00198
00199 #if 0
00200
00201 if (cb_qop)
00202 state->qop = cb_qop (sctx, serverqop);
00203
00204 if ((state->qop & serverqop) == 0)
00205
00206 return GSASL_GSSAPI_UNSUPPORTED_PROTECTION_ERROR;
00207 #endif
00208
00209
00210
00211 p = gsasl_property_get (sctx, GSASL_AUTHID);
00212 if (!p)
00213 return GSASL_NO_AUTHID;
00214
00215 bufdesc.length = 4 + strlen (p);
00216 bufdesc.value = malloc (bufdesc.length);
00217 if (!bufdesc.value)
00218 return GSASL_MALLOC_ERROR;
00219
00220 {
00221 char *q = bufdesc.value;
00222 q[0] = state->qop;
00223 memcpy (q + 1, clientwrap + 1, 3);
00224 memcpy (q + 4, p, strlen (p));
00225 }
00226
00227 maj_stat = gss_wrap (&min_stat, state->context, 0, GSS_C_QOP_DEFAULT,
00228 &bufdesc, &conf_state, &bufdesc2);
00229 free (bufdesc.value);
00230 if (GSS_ERROR (maj_stat))
00231 return GSASL_GSSAPI_WRAP_ERROR;
00232
00233 *output_len = bufdesc2.length;
00234 *output = malloc (bufdesc2.length);
00235 if (!*output)
00236 return GSASL_MALLOC_ERROR;
00237
00238 memcpy (*output, bufdesc2.value, bufdesc2.length);
00239
00240 maj_stat = gss_release_buffer (&min_stat, &bufdesc2);
00241 if (GSS_ERROR (maj_stat))
00242 return GSASL_GSSAPI_RELEASE_BUFFER_ERROR;
00243
00244 state->step++;
00245 res = GSASL_OK;
00246 break;
00247
00248 default:
00249 res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
00250 break;
00251 }
00252
00253 return res;
00254 }
00255
00256 void
00257 _gsasl_gssapi_client_finish (Gsasl_session * sctx, void *mech_data)
00258 {
00259 _Gsasl_gssapi_client_state *state = mech_data;
00260 OM_uint32 maj_stat, min_stat;
00261
00262 if (!state)
00263 return;
00264
00265 if (state->service != GSS_C_NO_NAME)
00266 maj_stat = gss_release_name (&min_stat, &state->service);
00267 if (state->context != GSS_C_NO_CONTEXT)
00268 maj_stat = gss_delete_sec_context (&min_stat, &state->context,
00269 GSS_C_NO_BUFFER);
00270
00271 free (state);
00272 }
00273
00274 int
00275 _gsasl_gssapi_client_encode (Gsasl_session * sctx,
00276 void *mech_data,
00277 const char *input, size_t input_len,
00278 char **output, size_t * output_len)
00279 {
00280 _Gsasl_gssapi_client_state *state = mech_data;
00281 OM_uint32 min_stat, maj_stat;
00282 gss_buffer_desc foo;
00283 gss_buffer_t input_message_buffer = &foo;
00284 gss_buffer_desc output_message_buffer;
00285
00286 foo.length = input_len;
00287 foo.value = (void *) input;
00288
00289 if (state && state->step == 3 &&
00290 state->qop & (GSASL_QOP_AUTH_INT | GSASL_QOP_AUTH_CONF))
00291 {
00292 maj_stat = gss_wrap (&min_stat,
00293 state->context,
00294 state->qop & GSASL_QOP_AUTH_CONF ? 1 : 0,
00295 GSS_C_QOP_DEFAULT,
00296 input_message_buffer,
00297 NULL, &output_message_buffer);
00298 if (GSS_ERROR (maj_stat))
00299 return GSASL_GSSAPI_WRAP_ERROR;
00300 *output_len = output_message_buffer.length;
00301 *output = malloc (input_len);
00302 if (!*output)
00303 {
00304 maj_stat = gss_release_buffer (&min_stat, &output_message_buffer);
00305 return GSASL_MALLOC_ERROR;
00306 }
00307 memcpy (*output, output_message_buffer.value,
00308 output_message_buffer.length);
00309
00310 maj_stat = gss_release_buffer (&min_stat, &output_message_buffer);
00311 if (GSS_ERROR (maj_stat))
00312 {
00313 free (*output);
00314 return GSASL_GSSAPI_RELEASE_BUFFER_ERROR;
00315 }
00316 }
00317 else
00318 {
00319 *output_len = input_len;
00320 *output = malloc (input_len);
00321 if (!*output)
00322 return GSASL_MALLOC_ERROR;
00323 memcpy (*output, input, input_len);
00324 }
00325
00326 return GSASL_OK;
00327 }
00328
00329 int
00330 _gsasl_gssapi_client_decode (Gsasl_session * sctx,
00331 void *mech_data,
00332 const char *input, size_t input_len,
00333 char **output, size_t * output_len)
00334 {
00335 _Gsasl_gssapi_client_state *state = mech_data;
00336 OM_uint32 min_stat, maj_stat;
00337 gss_buffer_desc foo;
00338 gss_buffer_t input_message_buffer = &foo;
00339 gss_buffer_desc output_message_buffer;
00340
00341 foo.length = input_len;
00342 foo.value = (void *) input;
00343
00344 if (state && state->step == 3 &&
00345 state->qop & (GSASL_QOP_AUTH_INT | GSASL_QOP_AUTH_CONF))
00346 {
00347 maj_stat = gss_unwrap (&min_stat,
00348 state->context,
00349 input_message_buffer,
00350 &output_message_buffer, NULL, NULL);
00351 if (GSS_ERROR (maj_stat))
00352 return GSASL_GSSAPI_UNWRAP_ERROR;
00353 *output_len = output_message_buffer.length;
00354 *output = malloc (input_len);
00355 if (!*output)
00356 {
00357 maj_stat = gss_release_buffer (&min_stat, &output_message_buffer);
00358 return GSASL_MALLOC_ERROR;
00359 }
00360 memcpy (*output, output_message_buffer.value,
00361 output_message_buffer.length);
00362
00363 maj_stat = gss_release_buffer (&min_stat, &output_message_buffer);
00364 if (GSS_ERROR (maj_stat))
00365 {
00366 free (*output);
00367 return GSASL_GSSAPI_RELEASE_BUFFER_ERROR;
00368 }
00369 }
00370 else
00371 {
00372 *output_len = input_len;
00373 *output = malloc (input_len);
00374 if (!*output)
00375 return GSASL_MALLOC_ERROR;
00376 memcpy (*output, input, input_len);
00377 }
00378
00379 return GSASL_OK;
00380 }