run_editor(): also compare size when deciding "has changed"
[s-mailx.git] / smtp_gssapi.h
blobde2c2a43f3f5ee337aedde144ab0306c35d4d281
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". TODO LEAKS (error path)
5 * Copyright (c) 2014 Steffen (Daode) Nurpmeso <sdaoden@users.sf.net>.
6 */
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
15 * are met:
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
39 * SUCH DAMAGE.
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.
72 #ifdef HAVE_GSSAPI
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 # endif
79 #else
80 # include <gssapi.h>
81 #endif
83 static void _smtp_gssapi_error1(char const *s, OM_uint32 code, int typ);
84 static void _smtp_gssapi_error(char const *s, OM_uint32 maj_stat,
85 OM_uint32 min_stat);
87 static void
88 _smtp_gssapi_error1(char const *s, OM_uint32 code, int typ)
90 OM_uint32 maj_stat, min_stat;
91 gss_buffer_desc msg = GSS_C_EMPTY_BUFFER;
92 OM_uint32 msg_ctx = 0;
93 NYD_ENTER;
95 do {
96 maj_stat = gss_display_status(&min_stat, code, typ, GSS_C_NO_OID,
97 &msg_ctx, &msg);
98 if (maj_stat == GSS_S_COMPLETE) {
99 fprintf(stderr, "GSS error: %s / %s\n", s, (char*)msg.value);
100 if (msg.length != 0)
101 gss_release_buffer(&min_stat, &msg);
102 } else {
103 fprintf(stderr, "GSS error: %s / unknown\n", s);
104 break;
106 } while (msg_ctx);
107 NYD_LEAVE;
110 static void
111 _smtp_gssapi_error(char const *s, OM_uint32 maj_stat, OM_uint32 min_stat)
113 NYD_ENTER;
114 _smtp_gssapi_error1(s, maj_stat, GSS_C_GSS_CODE);
115 _smtp_gssapi_error1(s, min_stat, GSS_C_MECH_CODE);
116 NYD_LEAVE;
119 static bool_t
120 _smtp_gssapi(struct sock *sp, struct sendbundle *sbp, struct smtp_line *slp)
122 struct str in, out;
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;
127 int conf_state;
128 bool_t ok = FAL0;
129 NYD_ENTER;
131 send_tok.value = salloc(send_tok.length = sbp->sb_url.url_host.l + 5 +1);
132 memcpy(send_tok.value, "smtp@", 5);
133 memcpy((char*)send_tok.value + 5, sbp->sb_url.url_host.s,
134 sbp->sb_url.url_host.l +1);
136 maj_stat = gss_import_name(&min_stat, &send_tok, GSS_C_NT_HOSTBASED_SERVICE,
137 &target_name);
138 if (maj_stat != GSS_S_COMPLETE) {
139 _smtp_gssapi_error(send_tok.value, maj_stat, min_stat);
140 goto jleave;
143 token_ptr = GSS_C_NO_BUFFER;
144 gss_context = GSS_C_NO_CONTEXT;
145 maj_stat = gss_init_sec_context(&min_stat,
146 GSS_C_NO_CREDENTIAL,
147 &gss_context,
148 target_name,
149 GSS_C_NO_OID,
150 GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG,
152 GSS_C_NO_CHANNEL_BINDINGS,
153 token_ptr,
154 NULL,
155 &send_tok,
156 &ret_flags,
157 NULL);
158 if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED) {
159 _smtp_gssapi_error("initializing GSS context", maj_stat, min_stat);
160 gss_release_name(&min_stat, &target_name);
161 goto jleave;
164 _OUT(LINE("AUTH GSSAPI"));
165 _ANSWER(3, FAL0, FAL0);
166 while (maj_stat == GSS_S_CONTINUE_NEEDED) {
167 /* Pass token obtained from first gss_init_sec_context() call */
168 b64_encode_buf(&out, send_tok.value, send_tok.length,
169 B64_SALLOC | B64_CRLF);
170 gss_release_buffer(&min_stat, &send_tok);
171 _OUT(out.s);
172 _ANSWER(3, FAL0, TRU1);
174 out.s = NULL;
175 in.s = slp->dat;
176 in.l = slp->datlen;
177 b64_decode(&out, &in, NULL);
178 recv_tok.value = out.s;
179 recv_tok.length = out.l;
180 token_ptr = &recv_tok;
181 maj_stat = gss_init_sec_context(&min_stat,
182 GSS_C_NO_CREDENTIAL,
183 &gss_context,
184 target_name,
185 GSS_C_NO_OID,
186 GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG,
188 GSS_C_NO_CHANNEL_BINDINGS,
189 token_ptr,
190 NULL,
191 &send_tok,
192 &ret_flags,
193 NULL);
194 free(out.s);
195 if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED) {
196 _smtp_gssapi_error("initializing context", maj_stat, min_stat);
197 gss_release_name(&min_stat, &target_name);
198 goto jleave;
202 /* Pass token obtained from second gss_init_sec_context() call */
203 gss_release_name(&min_stat, &target_name);
204 b64_encode_buf(&out, send_tok.value, send_tok.length, B64_SALLOC | B64_CRLF);
205 gss_release_buffer(&min_stat, &send_tok);
206 _OUT(out.s);
208 _ANSWER(3, FAL0, TRU1);
209 out.s = NULL;
210 in.s = slp->dat;
211 in.l = slp->datlen;
212 b64_decode(&out, &in, NULL);
213 recv_tok.value = out.s;
214 recv_tok.length = out.l;
215 maj_stat = gss_unwrap(&min_stat, gss_context, &recv_tok, &send_tok,
216 &conf_state, NULL);
217 free(out.s);
218 if (maj_stat != GSS_S_COMPLETE) {
219 _smtp_gssapi_error("unwrapping data", maj_stat, min_stat);
220 goto jleave;
223 /* First octet: bit-mask with protection mechanisms (1 = no protection
224 * mechanism).
225 * Second to fourth octet: maximum message size in network byte order.
226 * Fifth and following octets: user name string */
227 in.s = salloc(send_tok.length = 4 + sbp->sb_ccred.cc_user.l +1);
228 memcpy(in.s + 4, sbp->sb_ccred.cc_user.s, sbp->sb_ccred.cc_user.l +1);
229 in.s[0] = 1;
230 in.s[1] = 0;
231 in.s[2] = in.s[3] = (char)0xFF;
232 send_tok.value = in.s;
233 maj_stat = gss_wrap(&min_stat, gss_context, 0, GSS_C_QOP_DEFAULT, &send_tok,
234 &conf_state, &recv_tok);
235 if (maj_stat != GSS_S_COMPLETE) {
236 _smtp_gssapi_error("wrapping data", maj_stat, min_stat);
237 goto jleave;
240 b64_encode_buf(&out, recv_tok.value, recv_tok.length, B64_SALLOC | B64_CRLF);
241 _OUT(out.s);
242 _ANSWER(2, FAL0, FAL0);
243 gss_delete_sec_context(&min_stat, &gss_context, &recv_tok);
244 gss_release_buffer(&min_stat, &recv_tok);
246 ok = TRU1;
247 jleave:
248 NYD_LEAVE;
249 return ok;
252 # undef GSS_C_NT_HOSTBASED_SERVICE
253 #endif /* HAVE_GSSAPI */
255 /* vim:set fenc=utf-8:s-it-mode */