Added to the repository
Showing
1 changed file
with
245 additions
and
0 deletions
imap4d/auth_gsasl.c
0 → 100644
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 2003 Free Software Foundation, Inc. | ||
3 | |||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | GNU Mailutils is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with GNU Mailutils; if not, write to the Free Software | ||
16 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ | ||
17 | |||
18 | #include "imap4d.h" | ||
19 | #include <gsasl.h> | ||
20 | #include <mailutils/gsasl.h> | ||
21 | |||
22 | static Gsasl_ctx *ctx; | ||
23 | static Gsasl_session_ctx *sess_ctx; | ||
24 | |||
25 | static int | ||
26 | create_gsasl_stream (stream_t *newstr, stream_t str, int flags) | ||
27 | { | ||
28 | int rc; | ||
29 | |||
30 | rc = gsasl_stream_create (newstr, str, sess_ctx, flags); | ||
31 | if (rc) | ||
32 | { | ||
33 | syslog (LOG_ERR, _("cannot create SASL stream: %s"), | ||
34 | mu_errstring (rc)); | ||
35 | return RESP_NO; | ||
36 | } | ||
37 | |||
38 | if ((rc = stream_open (*newstr)) != 0) | ||
39 | { | ||
40 | char *p; | ||
41 | if (stream_strerror (*newstr, &p)) | ||
42 | p = mu_errstring (rc); | ||
43 | syslog (LOG_ERR, _("cannot open SASL input stream: %s"), p); | ||
44 | return RESP_NO; | ||
45 | } | ||
46 | |||
47 | return RESP_OK; | ||
48 | } | ||
49 | |||
50 | |||
51 | static int | ||
52 | auth_gsasl (struct imap4d_command *command, | ||
53 | char *auth_type, char *arg, char **username) | ||
54 | { | ||
55 | char *input = NULL; | ||
56 | char output[512]; | ||
57 | size_t output_len; | ||
58 | char *s, *client_init; | ||
59 | int rc; | ||
60 | |||
61 | client_init = util_getword (arg, &s); | ||
62 | if (!client_init) | ||
63 | return RESP_BAD; | ||
64 | util_unquote (&client_init); | ||
65 | |||
66 | rc = gsasl_server_start (ctx, auth_type, &sess_ctx); | ||
67 | if (rc != GSASL_OK) | ||
68 | { | ||
69 | syslog (LOG_NOTICE, _("SASL gsasl_server_start: %s"), | ||
70 | gsasl_strerror(rc)); | ||
71 | return 0; | ||
72 | } | ||
73 | |||
74 | gsasl_server_application_data_set (sess_ctx, username); | ||
75 | |||
76 | input = client_init; | ||
77 | output[0] = '\0'; | ||
78 | output_len = sizeof (output); | ||
79 | |||
80 | while ((rc = gsasl_server_step_base64 (sess_ctx, input, output, output_len)) | ||
81 | == GSASL_NEEDS_MORE) | ||
82 | { | ||
83 | util_send ("+ %s\r\n", output); | ||
84 | input = imap4d_readline_ex (); | ||
85 | } | ||
86 | while (rc == GSASL_NEEDS_MORE); | ||
87 | |||
88 | if (rc != GSASL_OK) | ||
89 | { | ||
90 | syslog (LOG_NOTICE, _("GSASL error: %s"), gsasl_strerror (rc)); | ||
91 | return RESP_NO; | ||
92 | } | ||
93 | |||
94 | if (*username == NULL) | ||
95 | { | ||
96 | syslog (LOG_NOTICE, _("GSASL %s: cannot get username"), auth_type); | ||
97 | return RESP_NO; | ||
98 | } | ||
99 | |||
100 | if (sess_ctx) | ||
101 | { | ||
102 | stream_t in, out, new_in, new_out; | ||
103 | |||
104 | util_get_input (&in); | ||
105 | util_get_output (&out); | ||
106 | if (create_gsasl_stream (&new_in, in, MU_STREAM_READ)) | ||
107 | return RESP_NO; | ||
108 | if (create_gsasl_stream (&new_out, out, MU_STREAM_WRITE)) | ||
109 | { | ||
110 | stream_destroy (&new_in, stream_get_owner (new_in)); | ||
111 | return RESP_NO; | ||
112 | } | ||
113 | |||
114 | util_set_input (new_in); | ||
115 | util_set_output (new_out); | ||
116 | } | ||
117 | |||
118 | auth_gsasl_capa_init (1); | ||
119 | return RESP_OK; | ||
120 | } | ||
121 | |||
122 | static void | ||
123 | auth_gsasl_capa_init (int disable) | ||
124 | { | ||
125 | int rc; | ||
126 | char *listmech, *name, *s; | ||
127 | size_t size; | ||
128 | |||
129 | rc = gsasl_server_listmech (ctx, NULL, &size); | ||
130 | if (rc != GSASL_OK) | ||
131 | return; | ||
132 | |||
133 | listmech = malloc (size); | ||
134 | if (!listmech) | ||
135 | imap4d_bye (ERR_NO_MEM); | ||
136 | |||
137 | rc = gsasl_server_listmech (ctx, listmech, &size); | ||
138 | if (rc != GSASL_OK) | ||
139 | return; | ||
140 | |||
141 | for (name = strtok_r (listmech, " ", &s); name; | ||
142 | name = strtok_r (NULL, " ", &s)) | ||
143 | { | ||
144 | if (disable) | ||
145 | auth_remove (name); | ||
146 | else | ||
147 | auth_add (strdup (name), auth_gsasl); | ||
148 | } | ||
149 | |||
150 | free (listmech); | ||
151 | } | ||
152 | |||
153 | /* This is for DIGEST-MD5 */ | ||
154 | static int | ||
155 | cb_realm (Gsasl_session_ctx *ctx, char *out, size_t *outlen, size_t nth) | ||
156 | { | ||
157 | char *realm = util_localname (); | ||
158 | |||
159 | if (nth > 0) | ||
160 | return GSASL_NO_MORE_REALMS; | ||
161 | |||
162 | if (out) | ||
163 | { | ||
164 | if (*outlen < strlen (realm)) | ||
165 | return GSASL_TOO_SMALL_BUFFER; | ||
166 | memcpy (out, realm, strlen (realm)); | ||
167 | } | ||
168 | |||
169 | *outlen = strlen (realm); | ||
170 | |||
171 | return GSASL_OK; | ||
172 | } | ||
173 | |||
174 | static int | ||
175 | cb_validate (Gsasl_session_ctx *ctx, | ||
176 | const char *authorization_id, | ||
177 | const char *authentication_id, | ||
178 | const char *password) | ||
179 | { | ||
180 | char **username = gsasl_server_application_data_get (ctx); | ||
181 | *username = strdup (authentication_id ? | ||
182 | authentication_id : authorization_id); | ||
183 | return GSASL_OK; | ||
184 | } | ||
185 | |||
186 | #define GSSAPI_SERVICE "imap" | ||
187 | |||
188 | static int | ||
189 | cb_service (Gsasl_session_ctx *ctx, char *srv, size_t *srvlen, | ||
190 | char *host, size_t *hostlen) | ||
191 | { | ||
192 | char *hostname = util_localname (); | ||
193 | |||
194 | if (srv) | ||
195 | { | ||
196 | if (*srvlen < strlen (GSSAPI_SERVICE)) | ||
197 | return GSASL_TOO_SMALL_BUFFER; | ||
198 | |||
199 | memcpy (srv, GSSAPI_SERVICE, strlen (GSSAPI_SERVICE)); | ||
200 | } | ||
201 | |||
202 | if (srvlen) | ||
203 | *srvlen = strlen (GSSAPI_SERVICE); | ||
204 | |||
205 | if (host) | ||
206 | { | ||
207 | if (*hostlen < strlen (hostname)) | ||
208 | return GSASL_TOO_SMALL_BUFFER; | ||
209 | |||
210 | memcpy (host, hostname, strlen (hostname)); | ||
211 | } | ||
212 | |||
213 | if (hostlen) | ||
214 | *hostlen = strlen (hostname); | ||
215 | |||
216 | return GSASL_OK; | ||
217 | } | ||
218 | |||
219 | /* This gets called when SASL mechanism EXTERNAL is invoked */ | ||
220 | static int | ||
221 | cb_external (Gsasl_session_ctx *ctx) | ||
222 | { | ||
223 | return GSASL_AUTHENTICATION_ERROR; | ||
224 | } | ||
225 | |||
226 | void | ||
227 | auth_gsasl_init () | ||
228 | { | ||
229 | int rc; | ||
230 | |||
231 | rc = gsasl_init (&ctx); | ||
232 | if (rc != GSASL_OK) | ||
233 | { | ||
234 | syslog (LOG_NOTICE, _("cannot initialize libgsasl: %s"), | ||
235 | gsasl_strerror (rc)); | ||
236 | } | ||
237 | |||
238 | gsasl_server_callback_realm_set (ctx, cb_realm); | ||
239 | gsasl_server_callback_external_set (ctx, cb_external); | ||
240 | gsasl_server_callback_validate_set (ctx, cb_validate); | ||
241 | gsasl_server_callback_service_set (ctx, cb_service); | ||
242 | |||
243 | auth_gsasl_capa_init (0); | ||
244 | } | ||
245 |
-
Please register or sign in to post a comment