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