gsasl  2.2.1
openid20/server.c
Go to the documentation of this file.
1 /* server.c --- OPENID20 mechanism, server side.
2  * Copyright (C) 2011-2024 Simon Josefsson
3  *
4  * This file is part of GNU SASL Library.
5  *
6  * GNU SASL Library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public License
8  * as published by the Free Software Foundation; either version 2.1 of
9  * the License, or (at your option) any later version.
10  *
11  * GNU SASL Library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with GNU SASL Library; if not, write to the Free
18  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include <config.h>
24 
25 /* Get specification. */
26 #include "openid20.h"
27 
28 /* Get strdup, strlen. */
29 #include <string.h>
30 
31 /* Get calloc, free. */
32 #include <stdlib.h>
33 
34 /* Get _gsasl_parse_gs2_header. */
35 #include "mechtools.h"
36 
38 {
39  int step;
41 };
42 
43 int
45  void **mech_data)
46 {
47  struct openid20_server_state *state;
48 
49  state = (struct openid20_server_state *) calloc (sizeof (*state), 1);
50  if (state == NULL)
51  return GSASL_MALLOC_ERROR;
52 
53  *mech_data = state;
54 
55  return GSASL_OK;
56 }
57 
58 int
60  void *mech_data,
61  const char *input, size_t input_len,
62  char **output, size_t *output_len)
63 {
64  struct openid20_server_state *state = mech_data;
66 
67  *output_len = 0;
68  *output = NULL;
69 
70  switch (state->step)
71  {
72  case 0:
73  {
74  const char *p;
75  char *authzid;
76  size_t headerlen;
77 
78  if (input_len == 0)
79  return GSASL_NEEDS_MORE;
80 
81  res = _gsasl_parse_gs2_header (input, input_len,
82  &authzid, &headerlen);
83  if (res != GSASL_OK)
84  return res;
85 
86  if (authzid)
87  {
88  res = gsasl_property_set (sctx, GSASL_AUTHZID, authzid);
89  free (authzid);
90  if (res != GSASL_OK)
91  return res;
92  }
93 
94  input += headerlen;
95  input_len -= headerlen;
96 
97  res = gsasl_property_set_raw (sctx, GSASL_AUTHID, input, input_len);
98  if (res != GSASL_OK)
99  return res;
100 
102  if (!p || !*p)
104 
105  *output_len = strlen (p);
106  *output = malloc (*output_len);
107  if (!*output)
108  return GSASL_MALLOC_ERROR;
109 
110  memcpy (*output, p, *output_len);
111 
112  res = GSASL_NEEDS_MORE;
113  state->step++;
114  break;
115  }
116 
117  case 1:
118  {
119  const char *outcome_data;
120 
121  if (!(input_len == 1 && *input == '='))
123 
124  res = gsasl_callback (NULL, sctx, GSASL_VALIDATE_OPENID20);
125  if (res != GSASL_OK)
126  {
127  const char *failstr = "openid.error=fail";
128 
129  *output_len = strlen (failstr);
130  *output = strdup (failstr);
131  if (!*output)
132  return GSASL_MALLOC_ERROR;
133 
134  /* [RFC4422] Section 3.6 explicitly prohibits additional
135  information in an unsuccessful authentication outcome.
136  Therefore, the openid.error and openid.error_code are
137  to be sent as an additional challenge in the event of
138  an unsuccessful outcome. In this case, as the protocol
139  is lock step, the client will follow with an additional
140  exchange containing "=", after which the server will
141  respond with an application-level outcome. */
142 
143  state->allow_error_step = 1;
144  state->step++;
145  return GSASL_NEEDS_MORE;
146  }
147 
148  outcome_data = gsasl_property_get (sctx, GSASL_OPENID20_OUTCOME_DATA);
149  if (outcome_data)
150  {
151  *output = strdup (outcome_data);
152  if (!*output)
153  return GSASL_MALLOC_ERROR;
154  *output_len = strlen (*output);
155  }
156  else
157  {
158  *output = NULL;
159  *output_len = 0;
160  }
161 
162  res = GSASL_OK;
163  state->step++;
164  }
165  break;
166 
167  case 2:
168  {
169  /* We only get here when the previous step signalled an error
170  to the client. */
171 
172  if (!state->allow_error_step)
174 
175  if (!(input_len == 1 && *input == '='))
177 
179  state->step++;
180  }
181  break;
182 
183  default:
184  break;
185  }
186 
187  return res;
188 }
189 
190 void
192  void *mech_data)
193 {
194  struct openid20_server_state *state = mech_data;
195 
196  if (!state)
197  return;
198 
199  free (state);
200 }
int gsasl_callback(Gsasl *ctx, Gsasl_session *sctx, Gsasl_property prop)
Definition: callback.c:71
@ GSASL_OK
Definition: gsasl.h:129
@ GSASL_NO_OPENID20_REDIRECT_URL
Definition: gsasl.h:154
@ GSASL_AUTHENTICATION_ERROR
Definition: gsasl.h:138
@ GSASL_NEEDS_MORE
Definition: gsasl.h:130
@ GSASL_MALLOC_ERROR
Definition: gsasl.h:133
@ GSASL_MECHANISM_CALLED_TOO_MANY_TIMES
Definition: gsasl.h:132
@ GSASL_MECHANISM_PARSE_ERROR
Definition: gsasl.h:137
_GSASL_API int gsasl_property_set_raw(Gsasl_session *sctx, Gsasl_property prop, const char *data, size_t len)
Definition: property.c:218
_GSASL_API int gsasl_property_set(Gsasl_session *sctx, Gsasl_property prop, const char *data)
Definition: property.c:189
_GSASL_API const char * gsasl_property_get(Gsasl_session *sctx, Gsasl_property prop)
Definition: property.c:292
@ GSASL_AUTHZID
Definition: gsasl.h:225
@ GSASL_OPENID20_OUTCOME_DATA
Definition: gsasl.h:247
@ GSASL_VALIDATE_OPENID20
Definition: gsasl.h:259
@ GSASL_AUTHID
Definition: gsasl.h:224
@ GSASL_OPENID20_REDIRECT_URL
Definition: gsasl.h:246
int _gsasl_parse_gs2_header(const char *data, size_t len, char **authzid, size_t *headerlen)
Definition: mechtools.c:97
void _gsasl_openid20_server_finish(Gsasl_session *sctx _GL_UNUSED, void *mech_data)
int _gsasl_openid20_server_step(Gsasl_session *sctx, void *mech_data, const char *input, size_t input_len, char **output, size_t *output_len)
int _gsasl_openid20_server_start(Gsasl_session *sctx _GL_UNUSED, void **mech_data)