1/* server.c --- Non-standard SASL mechanism LOGIN, server side.
2 * Copyright (C) 2002-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 malloc, free. */
28#include <stdlib.h>
29
30/* Get strdup, strlen. */
31#include <string.h>
32
33/* Get specification. */
34#include "login.h"
35
36struct _Gsasl_login_server_state
37{
38 int step;
39 char *username;
40 char *password;
41};
42
43#define CHALLENGE_USERNAME "User Name"
44#define CHALLENGE_PASSWORD "Password"
45
46int
47_gsasl_login_server_start (Gsasl_session * sctx, void **mech_data)
48{
49 struct _Gsasl_login_server_state *state;
50
51 state = calloc (1, sizeof (*state));
52 if (state == NULL)
53 return GSASL_MALLOC_ERROR;
54
55 *mech_data = state;
56
57 return GSASL_OK;
58}
59
60int
61_gsasl_login_server_step (Gsasl_session * sctx,
62 void *mech_data,
63 const char *input, size_t input_len,
64 char **output, size_t * output_len)
65{
66 struct _Gsasl_login_server_state *state = mech_data;
67 int res;
68
69 switch (state->step)
70 {
71 case 0:
72 *output = strdup (CHALLENGE_USERNAME);
73 if (!*output)
74 return GSASL_MALLOC_ERROR;
75 *output_len = strlen (CHALLENGE_USERNAME);
76
77 state->step++;
78 res = GSASL_NEEDS_MORE;
79 break;
80
81 case 1:
82 if (input_len == 0)
83 return GSASL_MECHANISM_PARSE_ERROR;
84
85 state->username = malloc (input_len + 1);
86 if (state->username == NULL)
87 return GSASL_MALLOC_ERROR;
88
89 memcpy (state->username, input, input_len);
90 state->username[input_len] = '\0';
91
92 *output = strdup (CHALLENGE_PASSWORD);
93 if (!*output)
94 return GSASL_MALLOC_ERROR;
95 *output_len = strlen (CHALLENGE_PASSWORD);
96
97 state->step++;
98 res = GSASL_NEEDS_MORE;
99 break;
100
101 case 2:
102 if (input_len == 0)
103 return GSASL_MECHANISM_PARSE_ERROR;
104
105 state->password = malloc (input_len + 1);
106 if (state->password == NULL)
107 return GSASL_MALLOC_ERROR;
108
109 memcpy (state->password, input, input_len);
110 state->password[input_len] = '\0';
111
112 if (input_len != strlen (state->password))
113 return GSASL_MECHANISM_PARSE_ERROR;
114
115 gsasl_property_set (sctx, GSASL_AUTHID, state->username);
116 gsasl_property_set (sctx, GSASL_PASSWORD, state->password);
117
118 res = gsasl_callback (NULL, sctx, GSASL_VALIDATE_SIMPLE);
119 if (res == GSASL_NO_CALLBACK)
120 {
121 const char *key;
122
123 gsasl_property_set (sctx, GSASL_AUTHZID, NULL);
124 gsasl_property_set (sctx, GSASL_PASSWORD, NULL);
125
126 key = gsasl_property_get (sctx, GSASL_PASSWORD);
127
128 if (key && strlen (state->password) == strlen (key) &&
129 strcmp (state->password, key) == 0)
130 res = GSASL_OK;
131 else
132 res = GSASL_AUTHENTICATION_ERROR;
133 }
134
135 *output_len = 0;
136 *output = NULL;
137 state->step++;
138 break;
139
140 default:
141 res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
142 break;
143 }
144
145 return res;
146}
147
148void
149_gsasl_login_server_finish (Gsasl_session * sctx, void *mech_data)
150{
151 struct _Gsasl_login_server_state *state = mech_data;
152
153 if (!state)
154 return;
155
156 free (state->username);
157 free (state->password);
158 free (state);
159}
160