gsasl  2.2.1
openid20/client.c
Go to the documentation of this file.
1 /* client.c --- OPENID20 mechanism, client 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 bool. */
35 #include <stdbool.h>
36 
37 /* Get _gsasl_gs2_generate_header. */
38 #include "mechtools.h"
39 
41 {
42  int step;
43 };
44 
45 int
47  void **mech_data)
48 {
49  struct openid20_client_state *state;
50 
51  state = (struct openid20_client_state *) calloc (sizeof (*state), 1);
52  if (state == NULL)
53  return GSASL_MALLOC_ERROR;
54 
55  *mech_data = state;
56 
57  return GSASL_OK;
58 }
59 
60 int
62  void *mech_data,
63  const char *input, size_t input_len,
64  char **output, size_t *output_len)
65 {
66  struct openid20_client_state *state = mech_data;
68 
69  switch (state->step)
70  {
71  case 0:
72  {
73  const char *authzid = gsasl_property_get (sctx, GSASL_AUTHZID);
74  const char *authid = gsasl_property_get (sctx, GSASL_AUTHID);
75 
76  if (!authid || !*authid)
77  return GSASL_NO_AUTHID;
78 
79  res = _gsasl_gs2_generate_header (false, 'n', NULL, authzid,
80  strlen (authid), authid,
81  output, output_len);
82  if (res != GSASL_OK)
83  return res;
84 
85  res = GSASL_NEEDS_MORE;
86  state->step++;
87  }
88  break;
89 
90  case 1:
91  {
93  input, input_len);
94  if (res != GSASL_OK)
95  return res;
96 
97  res = gsasl_callback (NULL, sctx,
99  if (res != GSASL_OK)
100  return res;
101 
102  *output_len = 1;
103  *output = strdup ("=");
104  if (!*output)
105  return GSASL_MALLOC_ERROR;
106 
107  res = GSASL_OK;
108  state->step++;
109  }
110  break;
111 
112  /* This step is optional. The server could have approved
113  authentication already. Alternatively, it wanted to send
114  some SREGs or error data and we end up here. */
115  case 2:
116  {
118  input, input_len);
119  if (res != GSASL_OK)
120  return res;
121 
122  /* In the case of failures, the response MUST follow this
123  syntax:
124 
125  outcome_data = "openid.error" "=" sreg_val *( "," sregp_avp )
126 
127  [RFC4422] Section 3.6 explicitly prohibits additional information in
128  an unsuccessful authentication outcome. Therefore, the openid.error
129  and openid.error_code are to be sent as an additional challenge in
130  the event of an unsuccessful outcome. In this case, as the protocol
131  is lock step, the client will follow with an additional exchange
132  containing "=", after which the server will respond with an
133  application-level outcome.
134  */
135 
136 #define ERR_PREFIX "openid.error="
137  if (input_len > strlen (ERR_PREFIX)
138  && strncmp (ERR_PREFIX, input, strlen (ERR_PREFIX)) == 0)
139  {
140  *output_len = 1;
141  *output = strdup ("=");
142  if (!*output)
143  return GSASL_MALLOC_ERROR;
144 
145  res = GSASL_NEEDS_MORE;
146  }
147  else
148  {
149  *output_len = 0;
150  *output = NULL;
151 
152  res = GSASL_OK;
153  }
154 
155  state->step++;
156  }
157  break;
158 
159  default:
160  break;
161  }
162 
163  return res;
164 }
165 
166 void
168  void *mech_data)
169 {
170  struct openid20_client_state *state = mech_data;
171 
172  if (!state)
173  return;
174 
175  free (state);
176 }
int gsasl_callback(Gsasl *ctx, Gsasl_session *sctx, Gsasl_property prop)
Definition: callback.c:71
@ GSASL_OK
Definition: gsasl.h:129
@ 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_NO_AUTHID
Definition: gsasl.h:144
_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 const char * gsasl_property_get(Gsasl_session *sctx, Gsasl_property prop)
Definition: property.c:292
@ GSASL_AUTHZID
Definition: gsasl.h:225
@ GSASL_OPENID20_AUTHENTICATE_IN_BROWSER
Definition: gsasl.h:251
@ GSASL_OPENID20_OUTCOME_DATA
Definition: gsasl.h:247
@ GSASL_AUTHID
Definition: gsasl.h:224
@ GSASL_OPENID20_REDIRECT_URL
Definition: gsasl.h:246
int _gsasl_gs2_generate_header(bool nonstd, char cbflag, const char *cbname, const char *authzid, size_t extralen, const char *extra, char **gs2h, size_t *gs2hlen)
Definition: mechtools.c:166
void _gsasl_openid20_client_finish(Gsasl_session *sctx _GL_UNUSED, void *mech_data)
int _gsasl_openid20_client_start(Gsasl_session *sctx _GL_UNUSED, void **mech_data)
#define ERR_PREFIX
int _gsasl_openid20_client_step(Gsasl_session *sctx, void *mech_data, const char *input, size_t input_len, char **output, size_t *output_len)