1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
2 *@ Implementation of SMTP GSS-API authentication according to RFC 4954.
3 *@ TODO GSS-API should also be joined into "a VFS".
5 * Copyright (c) 2014 - 2018 Steffen (Daode) Nurpmeso <steffen@sdaoden.eu>.
8 /* Derived from `imap_gssapi.h', which is:
10 * Copyright (c) 2004 Gunnar Ritter.
11 * All rights reserved.
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. All advertising materials mentioning features or use of this software
22 * must display the following acknowledgement:
23 * This product includes software developed by Gunnar Ritter
24 * and his contributors.
25 * 4. Neither the name of Gunnar Ritter nor the names of his contributors
26 * may be used to endorse or promote products derived from this software
27 * without specific prior written permission.
29 * THIS SOFTWARE IS PROVIDED BY GUNNAR RITTER AND CONTRIBUTORS ``AS IS'' AND
30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32 * ARE DISCLAIMED. IN NO EVENT SHALL GUNNAR RITTER OR CONTRIBUTORS BE LIABLE
33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38 * 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 m_DEFINED_GCC_C_NT_HOSTBASED_SERVICE
84 static void _smtp_gssapi_error1(char const *s
, OM_uint32 code
, int typ
);
85 static void _smtp_gssapi_error(char const *s
, OM_uint32 maj_stat
,
89 _smtp_gssapi_error1(char const *s
, OM_uint32 code
, int typ
)
91 OM_uint32 maj_stat
, min_stat
;
92 gss_buffer_desc msg
= GSS_C_EMPTY_BUFFER
;
93 OM_uint32 msg_ctx
= 0;
97 maj_stat
= gss_display_status(&min_stat
, code
, typ
, GSS_C_NO_OID
,
99 if (maj_stat
== GSS_S_COMPLETE
) {
100 n_err(_("GSS error: %s / %s\n"), s
, (char*)msg
.value
);
101 gss_release_buffer(&min_stat
, &msg
);
103 n_err(_("GSS error: %s / unknown\n"), s
);
111 _smtp_gssapi_error(char const *s
, OM_uint32 maj_stat
, OM_uint32 min_stat
)
114 _smtp_gssapi_error1(s
, maj_stat
, GSS_C_GSS_CODE
);
115 _smtp_gssapi_error1(s
, min_stat
, GSS_C_MECH_CODE
);
120 _smtp_gssapi(struct sock
*sp
, struct sendbundle
*sbp
, struct smtp_line
*slp
)
123 gss_buffer_desc send_tok
, recv_tok
;
124 gss_name_t target_name
;
125 gss_ctx_id_t gss_context
;
126 OM_uint32 maj_stat
, min_stat
, ret_flags
;
130 a_F_RECV_TOK
= 1u<<0,
131 a_F_SEND_TOK
= 1u<<1,
132 a_F_TARGET_NAME
= 1u<<2,
133 a_F_GSS_CONTEXT
= 1u<<3
141 if(INT_MAX
- 1 - 4 <= sbp
->sb_ccred
.cc_user
.l
)
144 send_tok
.value
= salloc(send_tok
.length
= sbp
->sb_url
.url_host
.l
+ 5 +1);
145 memcpy(send_tok
.value
, "smtp@", 5);
146 memcpy((char*)send_tok
.value
+ 5, sbp
->sb_url
.url_host
.s
,
147 sbp
->sb_url
.url_host
.l
+1);
148 maj_stat
= gss_import_name(&min_stat
, &send_tok
, GSS_C_NT_HOSTBASED_SERVICE
,
150 f
|= a_F_TARGET_NAME
;
151 if (maj_stat
!= GSS_S_COMPLETE
) {
152 _smtp_gssapi_error(send_tok
.value
, maj_stat
, min_stat
);
156 gss_context
= GSS_C_NO_CONTEXT
;
157 maj_stat
= gss_init_sec_context(&min_stat
,
162 GSS_C_MUTUAL_FLAG
| GSS_C_SEQUENCE_FLAG
,
164 GSS_C_NO_CHANNEL_BINDINGS
,
170 f
|= a_F_SEND_TOK
| a_F_GSS_CONTEXT
;
171 if (maj_stat
!= GSS_S_COMPLETE
&& maj_stat
!= GSS_S_CONTINUE_NEEDED
) {
172 _smtp_gssapi_error("initializing GSS context", maj_stat
, min_stat
);
176 _OUT(NETLINE("AUTH GSSAPI"));
177 _ANSWER(3, FAL0
, FAL0
);
178 while (maj_stat
== GSS_S_CONTINUE_NEEDED
) {
179 /* Pass token obtained from first gss_init_sec_context() call */
180 if(b64_encode_buf(&out
, send_tok
.value
, send_tok
.length
,
181 B64_SALLOC
| B64_CRLF
) == NULL
)
183 gss_release_buffer(&min_stat
, &send_tok
);
186 _ANSWER(3, FAL0
, TRU1
);
191 if(!b64_decode(&out
, &in
))
193 recv_tok
.value
= out
.s
;
194 recv_tok
.length
= out
.l
;
195 maj_stat
= gss_init_sec_context(&min_stat
,
200 GSS_C_MUTUAL_FLAG
| GSS_C_SEQUENCE_FLAG
,
202 GSS_C_NO_CHANNEL_BINDINGS
,
210 if (maj_stat
!= GSS_S_COMPLETE
&& maj_stat
!= GSS_S_CONTINUE_NEEDED
) {
211 _smtp_gssapi_error("initializing context", maj_stat
, min_stat
);
216 gss_release_name(&min_stat
, &target_name
);
217 f
&= ~a_F_TARGET_NAME
;
219 /* Pass token obtained from second gss_init_sec_context() call */
220 if(b64_encode_buf(&out
, send_tok
.value
, send_tok
.length
,
221 B64_SALLOC
| B64_CRLF
) == NULL
)
225 gss_release_buffer(&min_stat
, &send_tok
);
228 _ANSWER(3, FAL0
, TRU1
);
232 if(!b64_decode(&out
, &in
)){
236 n_err(_("Invalid base64 encoding from GSSAPI server\n"));
239 recv_tok
.value
= out
.s
;
240 recv_tok
.length
= out
.l
;
241 maj_stat
= gss_unwrap(&min_stat
, gss_context
, &recv_tok
, &send_tok
,
244 gss_release_buffer(&min_stat
, &send_tok
);
245 /*f &= ~a_F_SEND_TOK;*/
246 if (maj_stat
!= GSS_S_COMPLETE
) {
247 _smtp_gssapi_error("unwrapping data", maj_stat
, min_stat
);
251 /* First octet: bit-mask with protection mechanisms (1 = no protection
253 * Second to fourth octet: maximum message size in network byte order.
254 * Fifth and following octets: user name string */
255 in
.s
= salloc(send_tok
.length
= 4 + sbp
->sb_ccred
.cc_user
.l
+1);
256 memcpy(in
.s
+ 4, sbp
->sb_ccred
.cc_user
.s
, sbp
->sb_ccred
.cc_user
.l
+1);
259 in
.s
[2] = in
.s
[3] = (char)0xFF;
260 send_tok
.value
= in
.s
;
261 maj_stat
= gss_wrap(&min_stat
, gss_context
, 0, GSS_C_QOP_DEFAULT
, &send_tok
,
262 &conf_state
, &recv_tok
);
264 if (maj_stat
!= GSS_S_COMPLETE
) {
265 _smtp_gssapi_error("wrapping data", maj_stat
, min_stat
);
269 if(b64_encode_buf(&out
, recv_tok
.value
, recv_tok
.length
,
270 B64_SALLOC
| B64_CRLF
) == NULL
)
273 _ANSWER(2, FAL0
, FAL0
);
278 gss_release_buffer(&min_stat
, &recv_tok
);
280 gss_release_buffer(&min_stat
, &send_tok
);
281 if(f
& a_F_TARGET_NAME
)
282 gss_release_name(&min_stat
, &target_name
);
283 if(f
& a_F_GSS_CONTEXT
)
284 gss_delete_sec_context(&min_stat
, &gss_context
, GSS_C_NO_BUFFER
);
289 # ifdef m_DEFINED_GCC_C_NT_HOSTBASED_SERVICE
290 # undef GSS_C_NT_HOSTBASED_SERVICE
292 #endif /* HAVE_GSSAPI */