Branch data Line data Source code
1 : : /* server.c --- OPENID20 mechanism, server side.
2 : : * Copyright (C) 2011-2012 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 : : #ifdef HAVE_CONFIG_H
24 : : #include "config.h"
25 : : #endif
26 : :
27 : : /* Get specification. */
28 : : #include "openid20.h"
29 : :
30 : : /* Get strdup, strlen. */
31 : : #include <string.h>
32 : :
33 : : /* Get calloc, free. */
34 : : #include <stdlib.h>
35 : :
36 : : /* Get _gsasl_parse_gs2_header. */
37 : : #include "mechtools.h"
38 : :
39 : : struct openid20_server_state
40 : : {
41 : : int step;
42 : : int allow_error_step;
43 : : };
44 : :
45 : : int
46 : 13 : _gsasl_openid20_server_start (Gsasl_session * sctx, void **mech_data)
47 : : {
48 : : struct openid20_server_state *state;
49 : :
50 : 13 : state = (struct openid20_server_state *) calloc (sizeof (*state), 1);
51 [ - + ]: 13 : if (state == NULL)
52 : 0 : return GSASL_MALLOC_ERROR;
53 : :
54 : 13 : *mech_data = state;
55 : :
56 : 13 : return GSASL_OK;
57 : : }
58 : :
59 : : int
60 : 25 : _gsasl_openid20_server_step (Gsasl_session * sctx,
61 : : void *mech_data,
62 : : const char *input, size_t input_len,
63 : : char **output, size_t * output_len)
64 : : {
65 : 25 : struct openid20_server_state *state = mech_data;
66 : 25 : int res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
67 : :
68 : 25 : *output_len = 0;
69 : 25 : *output = NULL;
70 : :
71 [ + + + - ]: 25 : switch (state->step)
72 : : {
73 : : case 0:
74 : : {
75 : : const char *p;
76 : : char *authzid;
77 : : size_t headerlen;
78 : :
79 [ + + ]: 15 : if (input_len == 0)
80 : 6 : return GSASL_NEEDS_MORE;
81 : :
82 : 9 : res = _gsasl_parse_gs2_header (input, input_len,
83 : : &authzid, &headerlen);
84 [ + + ]: 9 : if (res != GSASL_OK)
85 : 4 : return res;
86 : :
87 [ + + ]: 5 : if (authzid)
88 : : {
89 : 3 : gsasl_property_set (sctx, GSASL_AUTHZID, authzid);
90 : 3 : free (authzid);
91 : : }
92 : :
93 : 5 : input += headerlen;
94 : 5 : input_len -= headerlen;
95 : :
96 : 5 : gsasl_property_set_raw (sctx, GSASL_AUTHID, input, input_len);
97 : :
98 : 5 : p = gsasl_property_get (sctx, GSASL_OPENID20_REDIRECT_URL);
99 [ + - ][ - + ]: 5 : if (!p || !*p)
100 : 0 : return GSASL_NO_OPENID20_REDIRECT_URL;
101 : :
102 : 5 : *output_len = strlen (p);
103 : 5 : *output = malloc (*output_len);
104 [ - + ]: 5 : if (!*output)
105 : 0 : return GSASL_MALLOC_ERROR;
106 : :
107 : 5 : memcpy (*output, p, *output_len);
108 : :
109 : 5 : res = GSASL_NEEDS_MORE;
110 : 5 : state->step++;
111 : 5 : break;
112 : : }
113 : :
114 : : case 1:
115 : : {
116 : : const char *outcome_data;
117 : :
118 [ + - ][ - + ]: 5 : if (!(input_len == 1 && *input == '='))
119 : 0 : return GSASL_MECHANISM_PARSE_ERROR;
120 : :
121 : 5 : res = gsasl_callback (NULL, sctx, GSASL_VALIDATE_OPENID20);
122 [ + + ]: 5 : if (res != GSASL_OK)
123 : : {
124 : 1 : *output = strdup ("openid.error=fail");
125 [ - + ]: 1 : if (!*output)
126 : 0 : return GSASL_MALLOC_ERROR;
127 : 1 : *output_len = strlen (*output);
128 : :
129 : : /* [RFC4422] Section 3.6 explicitly prohibits additional
130 : : information in an unsuccessful authentication outcome.
131 : : Therefore, the openid.error and openid.error_code are
132 : : to be sent as an additional challenge in the event of
133 : : an unsuccessful outcome. In this case, as the protocol
134 : : is lock step, the client will follow with an additional
135 : : exchange containing "=", after which the server will
136 : : respond with an application-level outcome. */
137 : :
138 : 1 : state->allow_error_step = 1;
139 : 1 : state->step++;
140 : 1 : return GSASL_NEEDS_MORE;
141 : : }
142 : :
143 : 4 : outcome_data = gsasl_property_get (sctx, GSASL_OPENID20_OUTCOME_DATA);
144 [ + + ]: 4 : if (outcome_data)
145 : : {
146 : 3 : *output = strdup (outcome_data);
147 [ - + ]: 3 : if (!*output)
148 : 0 : return GSASL_MALLOC_ERROR;
149 : 3 : *output_len = strlen (*output);
150 : : }
151 : : else
152 : : {
153 : 1 : *output = NULL;
154 : 1 : *output_len = 0;
155 : : }
156 : :
157 : 4 : res = GSASL_OK;
158 : 4 : state->step++;
159 : : }
160 : 4 : break;
161 : :
162 : : case 2:
163 : : {
164 : : /* We only get here when the previous step signalled an error
165 : : to the client. */
166 : :
167 [ + + ]: 5 : if (!state->allow_error_step)
168 : 4 : return GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
169 : :
170 [ + - ][ - + ]: 1 : if (!(input_len == 1 && *input == '='))
171 : 0 : return GSASL_MECHANISM_PARSE_ERROR;
172 : :
173 : 1 : res = GSASL_AUTHENTICATION_ERROR;
174 : 1 : state->step++;
175 : : }
176 : 1 : break;
177 : :
178 : : default:
179 : 0 : break;
180 : : }
181 : :
182 : 25 : return res;
183 : : }
184 : :
185 : : void
186 : 13 : _gsasl_openid20_server_finish (Gsasl_session * sctx, void *mech_data)
187 : : {
188 : 13 : struct openid20_server_state *state = mech_data;
189 : :
190 [ - + ]: 13 : if (!state)
191 : 13 : return;
192 : :
193 : 13 : free (state);
194 : : }
|