2 * S-nail - a mail user agent derived from Berkeley Mail.
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
5 * Copyright (c) 2012 Steffen "Daode" Nurpmeso.
9 * Gunnar Ritter. All rights reserved.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by Gunnar Ritter
22 * and his contributors.
23 * 4. Neither the name of Gunnar Ritter nor the names of his contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY GUNNAR RITTER AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL GUNNAR RITTER OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
41 * Partially derived from sample code in:
43 * GSS-API Programming Guide
44 * Part No: 816-1331-11
45 * Sun Microsystems, Inc. 4150 Network Circle Santa Clara, CA 95054 U.S.A.
47 * (c) 2002 Sun Microsystems
50 * Copyright 1994 by OpenVision Technologies, Inc.
52 * Permission to use, copy, modify, distribute, and sell this software
53 * and its documentation for any purpose is hereby granted without fee,
54 * provided that the above copyright notice appears in all copies and
55 * that both that copyright notice and this permission notice appear in
56 * supporting documentation, and that the name of OpenVision not be used
57 * in advertising or publicity pertaining to distribution of the software
58 * without specific, written prior permission. OpenVision makes no
59 * representations about the suitability of this software for any
60 * purpose. It is provided "as is" without express or implied warranty.
62 * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
63 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
64 * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
65 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
66 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
67 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
68 * PERFORMANCE OF THIS SOFTWARE.
72 * Implementation of IMAP GSSAPI authentication according to RFC 1731.
77 #ifndef GSSAPI_REG_INCLUDE
78 #include <gssapi/gssapi.h>
79 #ifdef GSSAPI_OLD_STYLE
80 #include <gssapi/gssapi_generic.h>
81 #define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name
82 #endif /* GSSAPI_OLD_STYLE */
83 #else /* GSSAPI_REG_INCLUDE */
85 #endif /* GSSAPI_REG_INCLUDE */
87 static void imap_gss_error1(const char *s
, OM_uint32 code
, int type
);
88 static void imap_gss_error(const char *s
, OM_uint32 maj_stat
,
91 imap_gss_error1(const char *s
, OM_uint32 code
, int type
)
93 OM_uint32 maj_stat
, min_stat
;
94 gss_buffer_desc msg
= GSS_C_EMPTY_BUFFER
;
95 OM_uint32 msg_ctx
= 0;
98 maj_stat
= gss_display_status(&min_stat
, code
, type
,
99 GSS_C_NO_OID
, &msg_ctx
, &msg
);
100 if (maj_stat
== GSS_S_COMPLETE
) {
101 fprintf(stderr
, "GSS error: %s / %s\n",
105 gss_release_buffer(&min_stat
, &msg
);
107 fprintf(stderr
, "GSS error: %s / unknown\n", s
);
114 imap_gss_error(const char *s
, OM_uint32 maj_stat
, OM_uint32 min_stat
)
116 imap_gss_error1(s
, maj_stat
, GSS_C_GSS_CODE
);
117 imap_gss_error1(s
, min_stat
, GSS_C_MECH_CODE
);
121 imap_gss(struct mailbox
*mp
, char *user
)
123 gss_buffer_desc send_tok
, recv_tok
, *token_ptr
;
124 gss_name_t target_name
;
125 gss_ctx_id_t gss_context
;
126 OM_uint32 maj_stat
, min_stat
, ret_flags
;
129 FILE *queuefp
= NULL
;
134 if (user
== NULL
&& (user
= getuser()) == NULL
)
136 server
= salloc(strlen(mp
->mb_imap_account
));
137 strcpy(server
, mp
->mb_imap_account
);
138 if (strncmp(server
, "imap://", 7) == 0)
140 else if (strncmp(server
, "imaps://", 8) == 0)
142 if ((cp
= last_at_before_slash(server
)) != NULL
)
144 for (cp
= server
; *cp
; cp
++)
145 *cp
= lowerconv(*cp
&0377);
146 send_tok
.value
= salloc(send_tok
.length
= strlen(server
) + 6);
147 snprintf(send_tok
.value
, send_tok
.length
, "imap@%s", server
);
148 maj_stat
= gss_import_name(&min_stat
, &send_tok
,
149 GSS_C_NT_HOSTBASED_SERVICE
, &target_name
);
150 if (maj_stat
!= GSS_S_COMPLETE
) {
151 imap_gss_error(send_tok
.value
, maj_stat
, min_stat
);
154 token_ptr
= GSS_C_NO_BUFFER
;
155 gss_context
= GSS_C_NO_CONTEXT
;
156 maj_stat
= gss_init_sec_context(&min_stat
,
161 GSS_C_MUTUAL_FLAG
|GSS_C_SEQUENCE_FLAG
,
163 GSS_C_NO_CHANNEL_BINDINGS
,
169 if (maj_stat
!= GSS_S_COMPLETE
&& maj_stat
!= GSS_S_CONTINUE_NEEDED
) {
170 imap_gss_error("initializing GSS context", maj_stat
, min_stat
);
171 gss_release_name(&min_stat
, &target_name
);
174 snprintf(o
, sizeof o
, "%s AUTHENTICATE GSSAPI\r\n", tag(1));
175 IMAP_OUT(o
, 0, return STOP
);
177 * No response data expected.
180 if (response_type
!= RESPONSE_CONT
)
182 while (maj_stat
== GSS_S_CONTINUE_NEEDED
) {
184 * Pass token obtained from first gss_init_sec_context() call.
186 cp
= memtob64(send_tok
.value
, send_tok
.length
);
187 gss_release_buffer(&min_stat
, &send_tok
);
188 snprintf(o
, sizeof o
, "%s\r\n", cp
);
190 IMAP_OUT(o
, 0, return STOP
);
192 if (response_type
!= RESPONSE_CONT
)
194 in
.s
= responded_text
;
195 in
.l
= strlen(responded_text
);
196 mime_fromb64(&in
, &out
, 0);
197 recv_tok
.value
= out
.s
;
198 recv_tok
.length
= out
.l
;
199 token_ptr
= &recv_tok
;
200 maj_stat
= gss_init_sec_context(&min_stat
,
205 GSS_C_MUTUAL_FLAG
|GSS_C_SEQUENCE_FLAG
,
207 GSS_C_NO_CHANNEL_BINDINGS
,
213 if (maj_stat
!= GSS_S_COMPLETE
&&
214 maj_stat
!= GSS_S_CONTINUE_NEEDED
) {
215 imap_gss_error("initializing context",
217 gss_release_name(&min_stat
, &target_name
);
223 * Pass token obtained from second gss_init_sec_context() call.
225 gss_release_name(&min_stat
, &target_name
);
226 cp
= memtob64(send_tok
.value
, send_tok
.length
);
227 gss_release_buffer(&min_stat
, &send_tok
);
228 snprintf(o
, sizeof o
, "%s\r\n", cp
);
230 IMAP_OUT(o
, 0, return STOP
);
232 * First octet: bit-mask with protection mechanisms.
233 * Second to fourth octet: maximum message size in network byte order.
235 * This code currently does not care about the values.
238 if (response_type
!= RESPONSE_CONT
)
240 in
.s
= responded_text
;
241 in
.l
= strlen(responded_text
);
242 mime_fromb64(&in
, &out
, 0);
243 recv_tok
.value
= out
.s
;
244 recv_tok
.length
= out
.l
;
245 maj_stat
= gss_unwrap(&min_stat
, gss_context
, &recv_tok
,
246 &send_tok
, &conf_state
, NULL
);
247 if (maj_stat
!= GSS_S_COMPLETE
) {
248 imap_gss_error("unwrapping data", maj_stat
, min_stat
);
253 * First octet: bit-mask with protection mechanisms (1 = no protection
255 * Second to fourth octet: maximum message size in network byte order.
256 * Fifth and following octets: user name string.
260 o
[2] = o
[3] = (char)0377;
261 snprintf(&o
[4], sizeof o
- 4, "%s", user
);
263 send_tok
.length
= strlen(&o
[4]) + 5;
264 maj_stat
= gss_wrap(&min_stat
, gss_context
, 0, GSS_C_QOP_DEFAULT
,
265 &send_tok
, &conf_state
, &recv_tok
);
266 if (maj_stat
!= GSS_S_COMPLETE
) {
267 imap_gss_error("wrapping data", maj_stat
, min_stat
);
270 cp
= memtob64(recv_tok
.value
, recv_tok
.length
);
271 snprintf(o
, sizeof o
, "%s\r\n", cp
);
273 IMAP_OUT(o
, MB_COMD
, return STOP
);
274 while (mp
->mb_active
& MB_COMD
)
275 ok
= imap_answer(mp
, 1);
276 gss_delete_sec_context(&min_stat
, &gss_context
, &recv_tok
);
277 gss_release_buffer(&min_stat
, &recv_tok
);
281 #endif /* USE_GSSAPI */