Allow full "RFC 5322 address"es for -b and -c..
[s-mailx.git] / imap_gssapi.c
blob68bf15440af7593743d8709f6af8b21bf7f9bf5b
1 /*
2 * Heirloom mailx - 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.
6 */
7 /*
8 * Copyright (c) 2004
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
13 * are met:
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
37 * SUCH DAMAGE.
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.
71 #ifndef lint
72 #ifdef DOSCCS
73 static char sccsid[] = "@(#)imap_gssapi.c 1.10 (gritter) 3/4/06";
74 #endif
75 #endif /* not lint */
78 * Implementation of IMAP GSSAPI authentication according to RFC 1731.
81 #ifdef USE_GSSAPI
83 #ifndef GSSAPI_REG_INCLUDE
84 #include <gssapi/gssapi.h>
85 #ifdef GSSAPI_OLD_STYLE
86 #include <gssapi/gssapi_generic.h>
87 #define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name
88 #endif /* GSSAPI_OLD_STYLE */
89 #else /* GSSAPI_REG_INCLUDE */
90 #include <gssapi.h>
91 #endif /* GSSAPI_REG_INCLUDE */
93 static void imap_gss_error1(const char *s, OM_uint32 code, int type);
94 static void imap_gss_error(const char *s, OM_uint32 maj_stat,
95 OM_uint32 min_stat);
96 static void
97 imap_gss_error1(const char *s, OM_uint32 code, int type)
99 OM_uint32 maj_stat, min_stat;
100 gss_buffer_desc msg = GSS_C_EMPTY_BUFFER;
101 OM_uint32 msg_ctx = 0;
103 do {
104 maj_stat = gss_display_status(&min_stat, code, type,
105 GSS_C_NO_OID, &msg_ctx, &msg);
106 if (maj_stat == GSS_S_COMPLETE) {
107 fprintf(stderr, "GSS error: %s / %s\n",
109 (char *)msg.value);
110 if (msg.length != 0)
111 gss_release_buffer(&min_stat, &msg);
112 } else {
113 fprintf(stderr, "GSS error: %s / unknown\n", s);
114 break;
116 } while (msg_ctx);
119 static void
120 imap_gss_error(const char *s, OM_uint32 maj_stat, OM_uint32 min_stat)
122 imap_gss_error1(s, maj_stat, GSS_C_GSS_CODE);
123 imap_gss_error1(s, min_stat, GSS_C_MECH_CODE);
126 static enum okay
127 imap_gss(struct mailbox *mp, char *user)
129 gss_buffer_desc send_tok, recv_tok, *token_ptr;
130 gss_name_t target_name;
131 gss_ctx_id_t gss_context;
132 OM_uint32 maj_stat, min_stat, ret_flags;
133 int conf_state;
134 struct str in, out;
135 FILE *queuefp = NULL;
136 char *server, *cp;
137 char o[LINESIZE];
138 enum okay ok = STOP;
140 if (user == NULL && (user = getuser()) == NULL)
141 return STOP;
142 server = salloc(strlen(mp->mb_imap_account));
143 strcpy(server, mp->mb_imap_account);
144 if (strncmp(server, "imap://", 7) == 0)
145 server += 7;
146 else if (strncmp(server, "imaps://", 8) == 0)
147 server += 8;
148 if ((cp = last_at_before_slash(server)) != NULL)
149 server = &cp[1];
150 for (cp = server; *cp; cp++)
151 *cp = lowerconv(*cp&0377);
152 send_tok.value = salloc(send_tok.length = strlen(server) + 6);
153 snprintf(send_tok.value, send_tok.length, "imap@%s", server);
154 maj_stat = gss_import_name(&min_stat, &send_tok,
155 GSS_C_NT_HOSTBASED_SERVICE, &target_name);
156 if (maj_stat != GSS_S_COMPLETE) {
157 imap_gss_error(send_tok.value, maj_stat, min_stat);
158 return STOP;
160 token_ptr = GSS_C_NO_BUFFER;
161 gss_context = GSS_C_NO_CONTEXT;
162 maj_stat = gss_init_sec_context(&min_stat,
163 GSS_C_NO_CREDENTIAL,
164 &gss_context,
165 target_name,
166 GSS_C_NO_OID,
167 GSS_C_MUTUAL_FLAG|GSS_C_SEQUENCE_FLAG,
169 GSS_C_NO_CHANNEL_BINDINGS,
170 token_ptr,
171 NULL,
172 &send_tok,
173 &ret_flags,
174 NULL);
175 if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED) {
176 imap_gss_error("initializing GSS context", maj_stat, min_stat);
177 gss_release_name(&min_stat, &target_name);
178 return STOP;
180 snprintf(o, sizeof o, "%s AUTHENTICATE GSSAPI\r\n", tag(1));
181 IMAP_OUT(o, 0, return STOP);
183 * No response data expected.
185 imap_answer(mp, 1);
186 if (response_type != RESPONSE_CONT)
187 return STOP;
188 while (maj_stat == GSS_S_CONTINUE_NEEDED) {
190 * Pass token obtained from first gss_init_sec_context() call.
192 cp = memtob64(send_tok.value, send_tok.length);
193 gss_release_buffer(&min_stat, &send_tok);
194 snprintf(o, sizeof o, "%s\r\n", cp);
195 free(cp);
196 IMAP_OUT(o, 0, return STOP);
197 imap_answer(mp, 1);
198 if (response_type != RESPONSE_CONT)
199 return STOP;
200 in.s = responded_text;
201 in.l = strlen(responded_text);
202 mime_fromb64(&in, &out, 0);
203 recv_tok.value = out.s;
204 recv_tok.length = out.l;
205 token_ptr = &recv_tok;
206 maj_stat = gss_init_sec_context(&min_stat,
207 GSS_C_NO_CREDENTIAL,
208 &gss_context,
209 target_name,
210 GSS_C_NO_OID,
211 GSS_C_MUTUAL_FLAG|GSS_C_SEQUENCE_FLAG,
213 GSS_C_NO_CHANNEL_BINDINGS,
214 token_ptr,
215 NULL,
216 &send_tok,
217 &ret_flags,
218 NULL);
219 if (maj_stat != GSS_S_COMPLETE &&
220 maj_stat != GSS_S_CONTINUE_NEEDED) {
221 imap_gss_error("initializing context",
222 maj_stat, min_stat);
223 gss_release_name(&min_stat, &target_name);
224 return STOP;
226 free(out.s);
229 * Pass token obtained from second gss_init_sec_context() call.
231 gss_release_name(&min_stat, &target_name);
232 cp = memtob64(send_tok.value, send_tok.length);
233 gss_release_buffer(&min_stat, &send_tok);
234 snprintf(o, sizeof o, "%s\r\n", cp);
235 free(cp);
236 IMAP_OUT(o, 0, return STOP);
238 * First octet: bit-mask with protection mechanisms.
239 * Second to fourth octet: maximum message size in network byte order.
241 * This code currently does not care about the values.
243 imap_answer(mp, 1);
244 if (response_type != RESPONSE_CONT)
245 return STOP;
246 in.s = responded_text;
247 in.l = strlen(responded_text);
248 mime_fromb64(&in, &out, 0);
249 recv_tok.value = out.s;
250 recv_tok.length = out.l;
251 maj_stat = gss_unwrap(&min_stat, gss_context, &recv_tok,
252 &send_tok, &conf_state, NULL);
253 if (maj_stat != GSS_S_COMPLETE) {
254 imap_gss_error("unwrapping data", maj_stat, min_stat);
255 return STOP;
257 free(out.s);
259 * First octet: bit-mask with protection mechanisms (1 = no protection
260 * mechanism).
261 * Second to fourth octet: maximum message size in network byte order.
262 * Fifth and following octets: user name string.
264 o[0] = 1;
265 o[1] = 0;
266 o[2] = o[3] = (char)0377;
267 snprintf(&o[4], sizeof o - 4, "%s", user);
268 send_tok.value = o;
269 send_tok.length = strlen(&o[4]) + 5;
270 maj_stat = gss_wrap(&min_stat, gss_context, 0, GSS_C_QOP_DEFAULT,
271 &send_tok, &conf_state, &recv_tok);
272 if (maj_stat != GSS_S_COMPLETE) {
273 imap_gss_error("wrapping data", maj_stat, min_stat);
274 return STOP;
276 cp = memtob64(recv_tok.value, recv_tok.length);
277 snprintf(o, sizeof o, "%s\r\n", cp);
278 free(cp);
279 IMAP_OUT(o, MB_COMD, return STOP);
280 while (mp->mb_active & MB_COMD)
281 ok = imap_answer(mp, 1);
282 gss_delete_sec_context(&min_stat, &gss_context, &recv_tok);
283 gss_release_buffer(&min_stat, &recv_tok);
284 return ok;
287 #endif /* USE_GSSAPI */