|
gsasl
1.8.0
|
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 }
1.7.6.1