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 "gs2.h"
00029
00030
00031 #include <stdlib.h>
00032
00033
00034 #include <string.h>
00035
00036 #include "gss-extra.h"
00037 #include "gs2helper.h"
00038
00039 struct _gsasl_gs2_client_state
00040 {
00041
00042 int step;
00043 gss_name_t service;
00044 gss_ctx_id_t context;
00045 gss_OID mech_oid;
00046 gss_buffer_desc token;
00047 struct gss_channel_bindings_struct cb;
00048 };
00049 typedef struct _gsasl_gs2_client_state _gsasl_gs2_client_state;
00050
00051
00052
00053 int
00054 _gsasl_gs2_client_start (Gsasl_session * sctx, void **mech_data)
00055 {
00056 _gsasl_gs2_client_state *state;
00057 int res;
00058
00059 state = (_gsasl_gs2_client_state *) malloc (sizeof (*state));
00060 if (state == NULL)
00061 return GSASL_MALLOC_ERROR;
00062
00063 res = gs2_get_oid (sctx, &state->mech_oid);
00064 if (res != GSASL_OK)
00065 {
00066 free (state);
00067 return res;
00068 }
00069
00070 state->step = 0;
00071 state->service = GSS_C_NO_NAME;
00072 state->context = GSS_C_NO_CONTEXT;
00073 state->token.length = 0;
00074 state->token.value = NULL;
00075
00076
00077
00078
00079 state->cb.initiator_addrtype = 0;
00080 state->cb.initiator_address.length = 0;
00081 state->cb.initiator_address.value = NULL;
00082 state->cb.acceptor_addrtype = 0;
00083 state->cb.acceptor_address.length = 0;
00084 state->cb.acceptor_address.value = NULL;
00085 state->cb.application_data.length = 0;
00086 state->cb.application_data.value = NULL;
00087
00088 *mech_data = state;
00089
00090 return GSASL_OK;
00091 }
00092
00093
00094
00095
00096 static char *
00097 escape_authzid (const char *str)
00098 {
00099 char *out = malloc (strlen (str) * 3 + 1);
00100 char *p = out;
00101
00102 if (!out)
00103 return NULL;
00104
00105 while (*str)
00106 {
00107 if (*str == ',')
00108 {
00109 memcpy (p, "=2C", 3);
00110 p += 3;
00111 }
00112 else if (*str == '=')
00113 {
00114 memcpy (p, "=3D", 3);
00115 p += 3;
00116 }
00117 else
00118 {
00119 *p = *str;
00120 p++;
00121 }
00122 str++;
00123 }
00124 *p = '\0';
00125
00126 return out;
00127 }
00128
00129
00130
00131
00132 static int
00133 prepare (Gsasl_session * sctx, _gsasl_gs2_client_state * state)
00134 {
00135 const char *service = gsasl_property_get (sctx, GSASL_SERVICE);
00136 const char *hostname = gsasl_property_get (sctx, GSASL_HOSTNAME);
00137 const char *authzid = gsasl_property_get (sctx, GSASL_AUTHZID);
00138 gss_buffer_desc bufdesc;
00139 OM_uint32 maj_stat, min_stat;
00140
00141 if (!service)
00142 return GSASL_NO_SERVICE;
00143 if (!hostname)
00144 return GSASL_NO_HOSTNAME;
00145
00146 bufdesc.length = asprintf ((char **) &bufdesc.value, "%s@%s",
00147 service, hostname);
00148 if (bufdesc.length <= 0 || bufdesc.value == NULL)
00149 return GSASL_MALLOC_ERROR;
00150
00151 maj_stat = gss_import_name (&min_stat, &bufdesc,
00152 GSS_C_NT_HOSTBASED_SERVICE, &state->service);
00153 free (bufdesc.value);
00154 if (GSS_ERROR (maj_stat))
00155 return GSASL_GSSAPI_IMPORT_NAME_ERROR;
00156
00157 if (authzid)
00158 {
00159 char *escaped_authzid = escape_authzid (authzid);
00160
00161 if (!escaped_authzid)
00162 return GSASL_MALLOC_ERROR;
00163
00164 state->cb.application_data.length
00165 = asprintf ((char **) &state->cb.application_data.value,
00166 "n,a=%s,", escaped_authzid);
00167
00168 free (escaped_authzid);
00169 }
00170 else
00171 {
00172 state->cb.application_data.value = strdup ("n,,");
00173 state->cb.application_data.length = 3;
00174 }
00175
00176 if (state->cb.application_data.length <= 0
00177 || state->cb.application_data.value == NULL)
00178 return GSASL_MALLOC_ERROR;
00179
00180 return GSASL_OK;
00181 }
00182
00183
00184
00185
00186
00187 static int
00188 token2output (Gsasl_session * sctx,
00189 _gsasl_gs2_client_state * state,
00190 const gss_buffer_t token, char **output, size_t * output_len)
00191 {
00192 OM_uint32 maj_stat, min_stat;
00193 gss_buffer_desc bufdesc;
00194
00195 if (state->step == 1)
00196 {
00197 state->step++;
00198
00199 maj_stat = gss_decapsulate_token (token, state->mech_oid, &bufdesc);
00200 if (GSS_ERROR (maj_stat))
00201 return GSASL_GSSAPI_ENCAPSULATE_TOKEN_ERROR;
00202
00203 *output_len = state->cb.application_data.length + bufdesc.length;
00204 *output = malloc (*output_len);
00205 if (!*output)
00206 {
00207 gss_release_buffer (&min_stat, &bufdesc);
00208 return GSASL_MALLOC_ERROR;
00209 }
00210
00211 memcpy (*output, state->cb.application_data.value,
00212 state->cb.application_data.length);
00213 memcpy (*output + state->cb.application_data.length,
00214 bufdesc.value, bufdesc.length);
00215
00216 maj_stat = gss_release_buffer (&min_stat, &bufdesc);
00217 if (GSS_ERROR (maj_stat))
00218 return GSASL_GSSAPI_RELEASE_BUFFER_ERROR;
00219 }
00220 else
00221 {
00222 *output_len = token->length;
00223 *output = malloc (*output_len);
00224 if (!*output)
00225 return GSASL_MALLOC_ERROR;
00226 memcpy (*output, token->value, token->length);
00227 }
00228
00229 return GSASL_OK;
00230 }
00231
00232
00233
00234
00235
00236 int
00237 _gsasl_gs2_client_step (Gsasl_session * sctx,
00238 void *mech_data,
00239 const char *input, size_t input_len,
00240 char **output, size_t * output_len)
00241 {
00242 _gsasl_gs2_client_state *state = mech_data;
00243 gss_buffer_desc bufdesc;
00244 gss_buffer_t buf = GSS_C_NO_BUFFER;
00245 OM_uint32 maj_stat, min_stat, ret_flags;
00246 gss_OID actual_mech_type;
00247 int res;
00248
00249 if (state->step > 2)
00250 return GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
00251
00252 if (state->step == 0)
00253 {
00254 res = prepare (sctx, state);
00255 if (res != GSASL_OK)
00256 return res;
00257 state->step++;
00258 }
00259
00260 if (state->step == 2)
00261 {
00262 bufdesc.length = input_len;
00263 bufdesc.value = (void *) input;
00264 buf = &bufdesc;
00265 }
00266
00267
00268 if (state->token.value != NULL)
00269 {
00270 maj_stat = gss_release_buffer (&min_stat, &state->token);
00271 if (GSS_ERROR (maj_stat))
00272 return GSASL_GSSAPI_RELEASE_BUFFER_ERROR;
00273
00274 state->token.value = NULL;
00275 state->token.length = 0;
00276 }
00277
00278 maj_stat = gss_init_sec_context (&min_stat,
00279 GSS_C_NO_CREDENTIAL,
00280 &state->context,
00281 state->service,
00282 state->mech_oid,
00283 GSS_C_MUTUAL_FLAG,
00284 0,
00285 &state->cb,
00286 buf,
00287 &actual_mech_type,
00288 &state->token, &ret_flags, NULL);
00289 if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED)
00290 return GSASL_GSSAPI_INIT_SEC_CONTEXT_ERROR;
00291
00292 res = token2output (sctx, state, &state->token, output, output_len);
00293 if (res != GSASL_OK)
00294 return res;
00295
00296 if (maj_stat == GSS_S_CONTINUE_NEEDED)
00297 return GSASL_NEEDS_MORE;
00298
00299
00300
00301
00302 if (!(ret_flags & GSS_C_MUTUAL_FLAG))
00303 return GSASL_AUTHENTICATION_ERROR;
00304
00305 if (!gss_oid_equal (state->mech_oid, actual_mech_type))
00306 return GSASL_AUTHENTICATION_ERROR;
00307
00308 state->step++;
00309 return GSASL_OK;
00310 }
00311
00312
00313
00314 void
00315 _gsasl_gs2_client_finish (Gsasl_session * sctx, void *mech_data)
00316 {
00317 _gsasl_gs2_client_state *state = mech_data;
00318 OM_uint32 maj_stat, min_stat;
00319
00320 if (!state)
00321 return;
00322
00323 if (state->token.value != NULL)
00324 maj_stat = gss_release_buffer (&min_stat, &state->token);
00325 if (state->service != GSS_C_NO_NAME)
00326 maj_stat = gss_release_name (&min_stat, &state->service);
00327 if (state->context != GSS_C_NO_CONTEXT)
00328 maj_stat = gss_delete_sec_context (&min_stat, &state->context,
00329 GSS_C_NO_BUFFER);
00330
00331 free (state->cb.application_data.value);
00332 free (state);
00333 }