1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
2 *@ Implementation of IMAP GSS-API authentication according to RFC 1731.
3 *@ TODO GSS-API should also be joined into "a VFS". TODO LEAKS (error path)
5 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
6 * Copyright (c) 2012 - 2015 Steffen (Daode) Nurpmeso <sdaoden@users.sf.net>.
9 * Copyright (c) 2004 Gunnar Ritter.
10 * All rights reserved.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by Gunnar Ritter
23 * and his contributors.
24 * 4. Neither the name of Gunnar Ritter nor the names of his contributors
25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission.
28 * THIS SOFTWARE IS PROVIDED BY GUNNAR RITTER AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL GUNNAR RITTER OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42 * Partially derived from sample code in:
44 * GSS-API Programming Guide
45 * Part No: 816-1331-11
46 * Sun Microsystems, Inc. 4150 Network Circle Santa Clara, CA 95054 U.S.A.
48 * (c) 2002 Sun Microsystems
51 * Copyright 1994 by OpenVision Technologies, Inc.
53 * Permission to use, copy, modify, distribute, and sell this software
54 * and its documentation for any purpose is hereby granted without fee,
55 * provided that the above copyright notice appears in all copies and
56 * that both that copyright notice and this permission notice appear in
57 * supporting documentation, and that the name of OpenVision not be used
58 * in advertising or publicity pertaining to distribution of the software
59 * without specific, written prior permission. OpenVision makes no
60 * representations about the suitability of this software for any
61 * purpose. It is provided "as is" without express or implied warranty.
63 * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
64 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
65 * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
66 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
67 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
68 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
69 * PERFORMANCE OF THIS SOFTWARE.
73 #ifndef GSSAPI_REG_INCLUDE
74 # include <gssapi/gssapi.h>
75 # ifdef GSSAPI_OLD_STYLE
76 # include <gssapi/gssapi_generic.h>
77 # define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name
78 # define NAIL_DEFINED_GCC_C_NT_HOSTBASED_SERVICE
84 static void _imap_gssapi_error1(const char *s
, OM_uint32 code
, int typ
);
85 static void _imap_gssapi_error(const char *s
, OM_uint32 maj_stat
,
87 static char * _imap_gssapi_last_at_before_slash(char const *sp
);
90 _imap_gssapi_error1(const char *s
, OM_uint32 code
, int typ
)
92 OM_uint32 maj_stat
, min_stat
;
93 gss_buffer_desc msg
= GSS_C_EMPTY_BUFFER
;
94 OM_uint32 msg_ctx
= 0;
98 maj_stat
= gss_display_status(&min_stat
, code
, typ
, GSS_C_NO_OID
,
100 if (maj_stat
== GSS_S_COMPLETE
) {
101 fprintf(stderr
, "GSS error: %s / %s\n", s
, (char*)msg
.value
);
103 gss_release_buffer(&min_stat
, &msg
);
105 fprintf(stderr
, "GSS error: %s / unknown\n", s
);
113 _imap_gssapi_error(const char *s
, OM_uint32 maj_stat
, OM_uint32 min_stat
)
116 _imap_gssapi_error1(s
, maj_stat
, GSS_C_GSS_CODE
);
117 _imap_gssapi_error1(s
, min_stat
, GSS_C_MECH_CODE
);
122 _imap_gssapi_last_at_before_slash(char const *sp
)
128 for (cp
= sp
; (c
= *cp
) != '\0'; ++cp
)
131 while (cp
> sp
&& *--cp
!= '@')
140 _imap_gssapi(struct mailbox
*mp
, struct ccred
*ccred
)
144 gss_buffer_desc send_tok
, recv_tok
, *token_ptr
;
145 gss_name_t target_name
;
146 gss_ctx_id_t gss_context
;
147 OM_uint32 maj_stat
, min_stat
, ret_flags
;
149 FILE *queuefp
= NULL
;
154 { size_t i
= strlen(mp
->mb_imap_account
) +1;
156 memcpy(server
, mp
->mb_imap_account
, i
);
158 if (!strncmp(server
, "imap://", 7))
160 else if (!strncmp(server
, "imaps://", 8))
162 if ((cp
= _imap_gssapi_last_at_before_slash(server
)) != NULL
)
164 for (cp
= server
; *cp
; cp
++)
165 *cp
= lowerconv(*cp
);
166 send_tok
.value
= salloc(send_tok
.length
= strlen(server
) + 6);
167 snprintf(send_tok
.value
, send_tok
.length
, "imap@%s", server
);
168 maj_stat
= gss_import_name(&min_stat
, &send_tok
, GSS_C_NT_HOSTBASED_SERVICE
,
170 if (maj_stat
!= GSS_S_COMPLETE
) {
171 _imap_gssapi_error(send_tok
.value
, maj_stat
, min_stat
);
174 token_ptr
= GSS_C_NO_BUFFER
;
175 gss_context
= GSS_C_NO_CONTEXT
;
176 maj_stat
= gss_init_sec_context(&min_stat
,
181 GSS_C_MUTUAL_FLAG
|GSS_C_SEQUENCE_FLAG
,
183 GSS_C_NO_CHANNEL_BINDINGS
,
189 if (maj_stat
!= GSS_S_COMPLETE
&& maj_stat
!= GSS_S_CONTINUE_NEEDED
) {
190 _imap_gssapi_error("initializing GSS context", maj_stat
, min_stat
);
191 gss_release_name(&min_stat
, &target_name
);
194 snprintf(o
, sizeof o
, "%s AUTHENTICATE GSSAPI\r\n", tag(1));
195 IMAP_OUT(o
, 0, return STOP
);
197 * No response data expected.
200 if (response_type
!= RESPONSE_CONT
)
202 while (maj_stat
== GSS_S_CONTINUE_NEEDED
) {
204 * Pass token obtained from first gss_init_sec_context() call.
206 b64_encode_buf(&out
, send_tok
.value
, send_tok
.length
,
207 B64_SALLOC
| B64_CRLF
);
208 gss_release_buffer(&min_stat
, &send_tok
);
209 IMAP_OUT(out
.s
, 0, return STOP
);
211 if (response_type
!= RESPONSE_CONT
)
214 in
.s
= responded_text
;
215 in
.l
= strlen(responded_text
);
216 b64_decode(&out
, &in
, NULL
);
217 recv_tok
.value
= out
.s
;
218 recv_tok
.length
= out
.l
;
219 token_ptr
= &recv_tok
;
220 maj_stat
= gss_init_sec_context(&min_stat
,
225 GSS_C_MUTUAL_FLAG
|GSS_C_SEQUENCE_FLAG
,
227 GSS_C_NO_CHANNEL_BINDINGS
,
234 if (maj_stat
!= GSS_S_COMPLETE
&& maj_stat
!= GSS_S_CONTINUE_NEEDED
) {
235 _imap_gssapi_error("initializing context", maj_stat
, min_stat
);
236 gss_release_name(&min_stat
, &target_name
);
241 * Pass token obtained from second gss_init_sec_context() call.
243 gss_release_name(&min_stat
, &target_name
);
244 b64_encode_buf(&out
, send_tok
.value
, send_tok
.length
, B64_SALLOC
| B64_CRLF
);
245 gss_release_buffer(&min_stat
, &send_tok
);
246 IMAP_OUT(out
.s
, 0, return STOP
);
248 * First octet: bit-mask with protection mechanisms.
249 * Second to fourth octet: maximum message size in network byte order.
251 * This code currently does not care about the values.
254 if (response_type
!= RESPONSE_CONT
)
257 in
.s
= responded_text
;
258 in
.l
= strlen(responded_text
);
259 b64_decode(&out
, &in
, NULL
);
260 recv_tok
.value
= out
.s
;
261 recv_tok
.length
= out
.l
;
262 maj_stat
= gss_unwrap(&min_stat
, gss_context
, &recv_tok
, &send_tok
,
265 if (maj_stat
!= GSS_S_COMPLETE
) {
266 _imap_gssapi_error("unwrapping data", maj_stat
, min_stat
);
270 * First octet: bit-mask with protection mechanisms (1 = no protection
272 * Second to fourth octet: maximum message size in network byte order.
273 * Fifth and following octets: user name string.
277 o
[2] = o
[3] = (char)0377;
278 snprintf(&o
[4], sizeof o
- 4, "%s", ccred
->cc_user
.s
);
280 send_tok
.length
= strlen(&o
[4]) + 5;
281 maj_stat
= gss_wrap(&min_stat
, gss_context
, 0, GSS_C_QOP_DEFAULT
, &send_tok
,
282 &conf_state
, &recv_tok
);
283 if (maj_stat
!= GSS_S_COMPLETE
) {
284 _imap_gssapi_error("wrapping data", maj_stat
, min_stat
);
287 b64_encode_buf(&out
, recv_tok
.value
, recv_tok
.length
, B64_SALLOC
| B64_CRLF
);
288 IMAP_OUT(out
.s
, MB_COMD
, return STOP
);
289 while (mp
->mb_active
& MB_COMD
)
290 ok
= imap_answer(mp
, 1);
291 gss_delete_sec_context(&min_stat
, &gss_context
, &recv_tok
);
292 gss_release_buffer(&min_stat
, &recv_tok
);
296 # ifdef NAIL_DEFINED_GCC_C_NT_HOSTBASED_SERVICE
297 # undef GSS_C_NT_HOSTBASED_SERVICE
299 #endif /* HAVE_GSSAPI */