gsasl  1.8.0
openid20/server.c
Go to the documentation of this file.
00001 /* server.c --- OPENID20 mechanism, server side.
00002  * Copyright (C) 2011-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 "openid20.h"
00029 
00030 /* Get strdup, strlen. */
00031 #include <string.h>
00032 
00033 /* Get calloc, free. */
00034 #include <stdlib.h>
00035 
00036 /* Get _gsasl_parse_gs2_header. */
00037 #include "mechtools.h"
00038 
00039 struct openid20_server_state
00040 {
00041   int step;
00042   int allow_error_step;
00043 };
00044 
00045 int
00046 _gsasl_openid20_server_start (Gsasl_session * sctx, void **mech_data)
00047 {
00048   struct openid20_server_state *state;
00049 
00050   state = (struct openid20_server_state *) calloc (sizeof (*state), 1);
00051   if (state == NULL)
00052     return GSASL_MALLOC_ERROR;
00053 
00054   *mech_data = state;
00055 
00056   return GSASL_OK;
00057 }
00058 
00059 int
00060 _gsasl_openid20_server_step (Gsasl_session * sctx,
00061                              void *mech_data,
00062                              const char *input, size_t input_len,
00063                              char **output, size_t * output_len)
00064 {
00065   struct openid20_server_state *state = mech_data;
00066   int res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
00067 
00068   *output_len = 0;
00069   *output = NULL;
00070 
00071   switch (state->step)
00072     {
00073     case 0:
00074       {
00075         const char *p;
00076         char *authzid;
00077         size_t headerlen;
00078 
00079         if (input_len == 0)
00080           return GSASL_NEEDS_MORE;
00081 
00082         res = _gsasl_parse_gs2_header (input, input_len,
00083                                        &authzid, &headerlen);
00084         if (res != GSASL_OK)
00085           return res;
00086 
00087         if (authzid)
00088           {
00089             gsasl_property_set (sctx, GSASL_AUTHZID, authzid);
00090             free (authzid);
00091           }
00092 
00093         input += headerlen;
00094         input_len -= headerlen;
00095 
00096         gsasl_property_set_raw (sctx, GSASL_AUTHID, input, input_len);
00097 
00098         p = gsasl_property_get (sctx, GSASL_OPENID20_REDIRECT_URL);
00099         if (!p || !*p)
00100           return GSASL_NO_OPENID20_REDIRECT_URL;
00101 
00102         *output_len = strlen (p);
00103         *output = malloc (*output_len);
00104         if (!*output)
00105           return GSASL_MALLOC_ERROR;
00106 
00107         memcpy (*output, p, *output_len);
00108 
00109         res = GSASL_NEEDS_MORE;
00110         state->step++;
00111         break;
00112       }
00113 
00114     case 1:
00115       {
00116         const char *outcome_data;
00117 
00118         if (!(input_len == 1 && *input == '='))
00119           return GSASL_MECHANISM_PARSE_ERROR;
00120 
00121         res = gsasl_callback (NULL, sctx, GSASL_VALIDATE_OPENID20);
00122         if (res != GSASL_OK)
00123           {
00124             *output = strdup ("openid.error=fail");
00125             if (!*output)
00126               return GSASL_MALLOC_ERROR;
00127             *output_len = strlen (*output);
00128 
00129             /* [RFC4422] Section 3.6 explicitly prohibits additional
00130                information in an unsuccessful authentication outcome.
00131                Therefore, the openid.error and openid.error_code are
00132                to be sent as an additional challenge in the event of
00133                an unsuccessful outcome.  In this case, as the protocol
00134                is lock step, the client will follow with an additional
00135                exchange containing "=", after which the server will
00136                respond with an application-level outcome. */
00137 
00138             state->allow_error_step = 1;
00139             state->step++;
00140             return GSASL_NEEDS_MORE;
00141           }
00142 
00143         outcome_data = gsasl_property_get (sctx, GSASL_OPENID20_OUTCOME_DATA);
00144         if (outcome_data)
00145           {
00146             *output = strdup (outcome_data);
00147             if (!*output)
00148               return GSASL_MALLOC_ERROR;
00149             *output_len = strlen (*output);
00150           }
00151         else
00152           {
00153             *output = NULL;
00154             *output_len = 0;
00155           }
00156 
00157         res = GSASL_OK;
00158         state->step++;
00159       }
00160       break;
00161 
00162     case 2:
00163       {
00164         /* We only get here when the previous step signalled an error
00165            to the client.  */
00166 
00167         if (!state->allow_error_step)
00168           return GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
00169 
00170         if (!(input_len == 1 && *input == '='))
00171           return GSASL_MECHANISM_PARSE_ERROR;
00172 
00173         res = GSASL_AUTHENTICATION_ERROR;
00174         state->step++;
00175       }
00176       break;
00177 
00178     default:
00179       break;
00180     }
00181 
00182   return res;
00183 }
00184 
00185 void
00186 _gsasl_openid20_server_finish (Gsasl_session * sctx, void *mech_data)
00187 {
00188   struct openid20_server_state *state = mech_data;
00189 
00190   if (!state)
00191     return;
00192 
00193   free (state);
00194 }