int _gsasl_anonymous_server_step (Gsasl_session * sctx, void *mech_data, const char *input, size_t input_len, char **output, size_t * output_len) { *output = NULL; *output_len = 0; if (!input) return GSASL_NEEDS_MORE; /* token = 1*255TCHAR The <token> production is restricted to 255 UTF-8 encoded Unicode characters. As the encoding of a characters uses a sequence of 1 to 4 octets, a token may be long as 1020 octets. */ if (input_len == 0 || input_len > 1020) return GSASL_MECHANISM_PARSE_ERROR; /* FIXME: Validate that input is UTF-8. */ gsasl_property_set_raw (sctx, GSASL_ANONYMOUS_TOKEN, input, input_len); return gsasl_callback (NULL, sctx, GSASL_VALIDATE_ANONYMOUS); }
/** * gsasl_callback: * @ctx: handle received from gsasl_init(), may be NULL to derive it * from @sctx. * @sctx: session handle. * @prop: enumerated value of Gsasl_property type. * * Invoke the application callback. The @prop value indicate what the * callback is expected to do. For example, for * GSASL_ANONYMOUS_TOKEN, the function is expected to invoke * gsasl_property_set(SCTX, GSASL_ANONYMOUS_TOKEN, "token") where * "token" is the anonymous token the application wishes the SASL * mechanism to use. See the manual for the meaning of all * parameters. * * Note that if no callback has been set by the application, but the * obsolete callback interface has been used, this function will * translate the old callback interface into the new. This interface * should be sufficient to invoke all callbacks, both new and old. * * Return value: Returns whatever the application callback return, or * GSASL_NO_CALLBACK if no application was known. * * Since: 0.2.0 **/ int gsasl_callback (Gsasl * ctx, Gsasl_session * sctx, Gsasl_property prop) { if (ctx == NULL && sctx == NULL) return GSASL_NO_CALLBACK; if (ctx == NULL) ctx = sctx->ctx; if (ctx->cb) return ctx->cb (ctx, sctx, prop); #ifndef GSASL_NO_OBSOLETE { /* Call obsolete callbacks. Remove this when the obsolete * callbacks are no longer supported. */ Gsasl_server_callback_anonymous cb_anonymous; Gsasl_server_callback_external cb_external; Gsasl_server_callback_securid cb_securid; Gsasl_server_callback_gssapi cb_gssapi; Gsasl_server_callback_validate cb_validate; Gsasl_server_callback_retrieve cb_retrieve; char buf[BUFSIZ]; size_t buflen = BUFSIZ - 1; int res; switch (prop) { case GSASL_VALIDATE_ANONYMOUS: if (!sctx->anonymous_token) break; cb_anonymous = gsasl_server_callback_anonymous_get (sctx->ctx); if (!cb_anonymous) break; res = cb_anonymous (sctx, sctx->anonymous_token); return res; break; case GSASL_VALIDATE_EXTERNAL: cb_external = gsasl_server_callback_external_get (sctx->ctx); if (!cb_external) break; res = cb_external (sctx); return res; break; case GSASL_VALIDATE_SECURID: cb_securid = gsasl_server_callback_securid_get (sctx->ctx); if (!cb_securid) break; res = cb_securid (sctx, sctx->authid, sctx->authzid, sctx->passcode, sctx->pin, buf, &buflen); if (buflen > 0 && buflen < BUFSIZ - 1) { buf[buflen] = '\0'; gsasl_property_set (sctx, GSASL_SUGGESTED_PIN, buf); } return res; break; case GSASL_VALIDATE_GSSAPI: cb_gssapi = gsasl_server_callback_gssapi_get (sctx->ctx); if (!cb_gssapi) break; res = cb_gssapi (sctx, sctx->gssapi_display_name, sctx->authzid); return res; break; case GSASL_VALIDATE_SIMPLE: cb_validate = gsasl_server_callback_validate_get (sctx->ctx); if (!cb_validate) break; res = cb_validate (sctx, sctx->authzid, sctx->authid, sctx->password); return res; break; case GSASL_PASSWORD: cb_retrieve = gsasl_server_callback_retrieve_get (sctx->ctx); if (!cb_retrieve) break; res = cb_retrieve (sctx, sctx->authid, sctx->authzid, sctx->hostname, &buf, &buflen); if (res == GSASL_OK) gsasl_property_set_raw (sctx, GSASL_PASSWORD, buf, buflen); /* FIXME else if (res == GSASL_TOO_SMALL_BUFFER)... */ return res; break; default: break; } } #endif return GSASL_NO_CALLBACK; }
int _gsasl_gssapi_server_step (Gsasl_session * sctx, void *mech_data, const char *input, size_t input_len, char **output, size_t * output_len) { _Gsasl_gssapi_server_state *state = mech_data; gss_buffer_desc bufdesc1, bufdesc2; OM_uint32 maj_stat, min_stat; gss_buffer_desc client_name; gss_OID mech_type; char tmp[4]; int res; *output = NULL; *output_len = 0; switch (state->step) { case 0: if (input_len == 0) { res = GSASL_NEEDS_MORE; break; } state->step++; /* fall through */ case 1: bufdesc1.value = (void *) input; bufdesc1.length = input_len; if (state->client) { gss_release_name (&min_stat, &state->client); state->client = GSS_C_NO_NAME; } maj_stat = gss_accept_sec_context (&min_stat, &state->context, state->cred, &bufdesc1, GSS_C_NO_CHANNEL_BINDINGS, &state->client, &mech_type, &bufdesc2, NULL, NULL, NULL); if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED) return GSASL_GSSAPI_ACCEPT_SEC_CONTEXT_ERROR; *output = malloc (bufdesc2.length); if (!*output) return GSASL_MALLOC_ERROR; memcpy (*output, bufdesc2.value, bufdesc2.length); *output_len = bufdesc2.length; maj_stat = gss_release_buffer (&min_stat, &bufdesc2); if (GSS_ERROR (maj_stat)) return GSASL_GSSAPI_RELEASE_BUFFER_ERROR; if (maj_stat == GSS_S_COMPLETE) state->step++; res = GSASL_NEEDS_MORE; break; case 2: memset (tmp, 0xFF, 4); tmp[0] = GSASL_QOP_AUTH; bufdesc1.length = 4; bufdesc1.value = tmp; maj_stat = gss_wrap (&min_stat, state->context, 0, GSS_C_QOP_DEFAULT, &bufdesc1, NULL, &bufdesc2); if (GSS_ERROR (maj_stat)) return GSASL_GSSAPI_WRAP_ERROR; *output = malloc (bufdesc2.length); if (!*output) return GSASL_MALLOC_ERROR; memcpy (*output, bufdesc2.value, bufdesc2.length); *output_len = bufdesc2.length; maj_stat = gss_release_buffer (&min_stat, &bufdesc2); if (GSS_ERROR (maj_stat)) return GSASL_GSSAPI_RELEASE_BUFFER_ERROR; state->step++; res = GSASL_NEEDS_MORE; break; case 3: bufdesc1.value = (void *) input; bufdesc1.length = input_len; maj_stat = gss_unwrap (&min_stat, state->context, &bufdesc1, &bufdesc2, NULL, NULL); if (GSS_ERROR (maj_stat)) return GSASL_GSSAPI_UNWRAP_ERROR; /* [RFC 2222 section 7.2.1]: The client passes this token to GSS_Unwrap and interprets the first octet of resulting cleartext as a bit-mask specifying the security layers supported by the server and the second through fourth octets as the maximum size output_message to send to the server. The client then constructs data, with the first octet containing the bit-mask specifying the selected security layer, the second through fourth octets containing in network byte order the maximum size output_message the client is able to receive, and the remaining octets containing the authorization identity. The client passes the data to GSS_Wrap with conf_flag set to FALSE, and responds with the generated output_message. The client can then consider the server authenticated. */ if ((((char *) bufdesc2.value)[0] & GSASL_QOP_AUTH) == 0) { /* Integrity or privacy unsupported */ maj_stat = gss_release_buffer (&min_stat, &bufdesc2); return GSASL_GSSAPI_UNSUPPORTED_PROTECTION_ERROR; } gsasl_property_set_raw (sctx, GSASL_AUTHZID, (char *) bufdesc2.value + 4, bufdesc2.length - 4); maj_stat = gss_display_name (&min_stat, state->client, &client_name, &mech_type); if (GSS_ERROR (maj_stat)) return GSASL_GSSAPI_DISPLAY_NAME_ERROR; gsasl_property_set_raw (sctx, GSASL_GSSAPI_DISPLAY_NAME, client_name.value, client_name.length); maj_stat = gss_release_buffer (&min_stat, &bufdesc2); if (GSS_ERROR (maj_stat)) return GSASL_GSSAPI_RELEASE_BUFFER_ERROR; res = gsasl_callback (NULL, sctx, GSASL_VALIDATE_GSSAPI); state->step++; break; default: res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES; break; } return res; }
/** * gsasl_property_set: * @sctx: session handle. * @prop: enumerated value of Gsasl_property type, indicating the * type of data in @data. * @data: zero terminated character string to store. * * Make a copy of @data and store it in the session handle for the * indicated property @prop. * * You can immediately deallocate @data after calling this function, * without affecting the data stored in the session handle. * * Since: 0.2.0 **/ void gsasl_property_set (Gsasl_session * sctx, Gsasl_property prop, const char *data) { gsasl_property_set_raw (sctx, prop, data, data ? strlen (data) : 0); }
int _gsasl_openid20_client_step (Gsasl_session * sctx, void *mech_data, const char *input, size_t input_len, char **output, size_t * output_len) { struct openid20_client_state *state = mech_data; int res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES; switch (state->step) { case 0: { const char *authzid = gsasl_property_get (sctx, GSASL_AUTHZID); const char *authid = gsasl_property_get (sctx, GSASL_AUTHID); if (!authid || !*authid) return GSASL_NO_AUTHID; res = _gsasl_gs2_generate_header (false, 'n', NULL, authzid, strlen (authid), authid, output, output_len); if (res != GSASL_OK) return res; res = GSASL_NEEDS_MORE; state->step++; } break; case 1: { gsasl_property_set_raw (sctx, GSASL_OPENID20_REDIRECT_URL, input, input_len); res = gsasl_callback (NULL, sctx, GSASL_OPENID20_AUTHENTICATE_IN_BROWSER); if (res != GSASL_OK) return res; *output_len = 1; *output = strdup ("="); if (!*output) return GSASL_MALLOC_ERROR; res = GSASL_OK; state->step++; } break; /* This step is optional. The server could have approved authentication already. Alternatively, it wanted to send some SREGs or error data and we end up here. */ case 2: { gsasl_property_set_raw (sctx, GSASL_OPENID20_OUTCOME_DATA, input, input_len); /* In the case of failures, the response MUST follow this syntax: outcome_data = "openid.error" "=" sreg_val *( "," sregp_avp ) [RFC4422] Section 3.6 explicitly prohibits additional information in an unsuccessful authentication outcome. Therefore, the openid.error and openid.error_code are to be sent as an additional challenge in the event of an unsuccessful outcome. In this case, as the protocol is lock step, the client will follow with an additional exchange containing "=", after which the server will respond with an application-level outcome. */ #define ERR_PREFIX "openid.error=" if (input_len > strlen (ERR_PREFIX) && strncmp (ERR_PREFIX, input, strlen (ERR_PREFIX)) == 0) { *output_len = 1; *output = strdup ("="); if (!*output) return GSASL_MALLOC_ERROR; res = GSASL_NEEDS_MORE; } else { *output_len = 0; *output = NULL; res = GSASL_OK; } state->step++; } break; default: break; } return res; }