cmd1.c: fix compiler warnings..
[s-mailx.git] / imap_gssapi.c
blob8f57729e2098e317e2f19e8c38b3b3c92f6c6097
1 /*
2 * Heirloom mailx - a mail user agent derived from Berkeley Mail.
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
5 */
6 /*
7 * Copyright (c) 2004
8 * Gunnar Ritter. All rights reserved.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by Gunnar Ritter
21 * and his contributors.
22 * 4. Neither the name of Gunnar Ritter nor the names of his contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
26 * THIS SOFTWARE IS PROVIDED BY GUNNAR RITTER AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL GUNNAR RITTER OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
40 * Partially derived from sample code in:
42 * GSS-API Programming Guide
43 * Part No: 816-1331-11
44 * Sun Microsystems, Inc. 4150 Network Circle Santa Clara, CA 95054 U.S.A.
46 * (c) 2002 Sun Microsystems
49 * Copyright 1994 by OpenVision Technologies, Inc.
51 * Permission to use, copy, modify, distribute, and sell this software
52 * and its documentation for any purpose is hereby granted without fee,
53 * provided that the above copyright notice appears in all copies and
54 * that both that copyright notice and this permission notice appear in
55 * supporting documentation, and that the name of OpenVision not be used
56 * in advertising or publicity pertaining to distribution of the software
57 * without specific, written prior permission. OpenVision makes no
58 * representations about the suitability of this software for any
59 * purpose. It is provided "as is" without express or implied warranty.
61 * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
62 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
63 * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
64 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
65 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
66 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
67 * PERFORMANCE OF THIS SOFTWARE.
70 #ifndef lint
71 #ifdef DOSCCS
72 static char sccsid[] = "@(#)imap_gssapi.c 1.10 (gritter) 3/4/06";
73 #endif
74 #endif /* not lint */
77 * Implementation of IMAP GSSAPI authentication according to RFC 1731.
80 #ifdef USE_GSSAPI
82 #ifndef GSSAPI_REG_INCLUDE
83 #include <gssapi/gssapi.h>
84 #ifdef GSSAPI_OLD_STYLE
85 #include <gssapi/gssapi_generic.h>
86 #define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name
87 #endif /* GSSAPI_OLD_STYLE */
88 #else /* GSSAPI_REG_INCLUDE */
89 #include <gssapi.h>
90 #endif /* GSSAPI_REG_INCLUDE */
92 static void imap_gss_error1(const char *s, OM_uint32 code, int type);
93 static void imap_gss_error(const char *s, OM_uint32 maj_stat,
94 OM_uint32 min_stat);
95 static void
96 imap_gss_error1(const char *s, OM_uint32 code, int type)
98 OM_uint32 maj_stat, min_stat;
99 gss_buffer_desc msg = GSS_C_EMPTY_BUFFER;
100 OM_uint32 msg_ctx = 0;
102 do {
103 maj_stat = gss_display_status(&min_stat, code, type,
104 GSS_C_NO_OID, &msg_ctx, &msg);
105 if (maj_stat == GSS_S_COMPLETE) {
106 fprintf(stderr, "GSS error: %s / %s\n",
108 (char *)msg.value);
109 if (msg.length != 0)
110 gss_release_buffer(&min_stat, &msg);
111 } else {
112 fprintf(stderr, "GSS error: %s / unknown\n", s);
113 break;
115 } while (msg_ctx);
118 static void
119 imap_gss_error(const char *s, OM_uint32 maj_stat, OM_uint32 min_stat)
121 imap_gss_error1(s, maj_stat, GSS_C_GSS_CODE);
122 imap_gss_error1(s, min_stat, GSS_C_MECH_CODE);
125 static enum okay
126 imap_gss(struct mailbox *mp, char *user)
128 gss_buffer_desc send_tok, recv_tok, *token_ptr;
129 gss_name_t target_name;
130 gss_ctx_id_t gss_context;
131 OM_uint32 maj_stat, min_stat, ret_flags;
132 int conf_state;
133 struct str in, out;
134 FILE *queuefp = NULL;
135 char *server, *cp;
136 char o[LINESIZE];
137 enum okay ok = STOP;
139 if (user == NULL && (user = getuser()) == NULL)
140 return STOP;
141 server = salloc(strlen(mp->mb_imap_account));
142 strcpy(server, mp->mb_imap_account);
143 if (strncmp(server, "imap://", 7) == 0)
144 server += 7;
145 else if (strncmp(server, "imaps://", 8) == 0)
146 server += 8;
147 if ((cp = last_at_before_slash(server)) != NULL)
148 server = &cp[1];
149 for (cp = server; *cp; cp++)
150 *cp = lowerconv(*cp&0377);
151 send_tok.value = salloc(send_tok.length = strlen(server) + 6);
152 snprintf(send_tok.value, send_tok.length, "imap@%s", server);
153 maj_stat = gss_import_name(&min_stat, &send_tok,
154 GSS_C_NT_HOSTBASED_SERVICE, &target_name);
155 if (maj_stat != GSS_S_COMPLETE) {
156 imap_gss_error(send_tok.value, maj_stat, min_stat);
157 return STOP;
159 token_ptr = GSS_C_NO_BUFFER;
160 gss_context = GSS_C_NO_CONTEXT;
161 maj_stat = gss_init_sec_context(&min_stat,
162 GSS_C_NO_CREDENTIAL,
163 &gss_context,
164 target_name,
165 GSS_C_NO_OID,
166 GSS_C_MUTUAL_FLAG|GSS_C_SEQUENCE_FLAG,
168 GSS_C_NO_CHANNEL_BINDINGS,
169 token_ptr,
170 NULL,
171 &send_tok,
172 &ret_flags,
173 NULL);
174 if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED) {
175 imap_gss_error("initializing GSS context", maj_stat, min_stat);
176 gss_release_name(&min_stat, &target_name);
177 return STOP;
179 snprintf(o, sizeof o, "%s AUTHENTICATE GSSAPI\r\n", tag(1));
180 IMAP_OUT(o, 0, return STOP);
182 * No response data expected.
184 imap_answer(mp, 1);
185 if (response_type != RESPONSE_CONT)
186 return STOP;
187 while (maj_stat == GSS_S_CONTINUE_NEEDED) {
189 * Pass token obtained from first gss_init_sec_context() call.
191 cp = memtob64(send_tok.value, send_tok.length);
192 gss_release_buffer(&min_stat, &send_tok);
193 snprintf(o, sizeof o, "%s\r\n", cp);
194 free(cp);
195 IMAP_OUT(o, 0, return STOP);
196 imap_answer(mp, 1);
197 if (response_type != RESPONSE_CONT)
198 return STOP;
199 in.s = responded_text;
200 in.l = strlen(responded_text);
201 mime_fromb64(&in, &out, 0);
202 recv_tok.value = out.s;
203 recv_tok.length = out.l;
204 token_ptr = &recv_tok;
205 maj_stat = gss_init_sec_context(&min_stat,
206 GSS_C_NO_CREDENTIAL,
207 &gss_context,
208 target_name,
209 GSS_C_NO_OID,
210 GSS_C_MUTUAL_FLAG|GSS_C_SEQUENCE_FLAG,
212 GSS_C_NO_CHANNEL_BINDINGS,
213 token_ptr,
214 NULL,
215 &send_tok,
216 &ret_flags,
217 NULL);
218 if (maj_stat != GSS_S_COMPLETE &&
219 maj_stat != GSS_S_CONTINUE_NEEDED) {
220 imap_gss_error("initializing context",
221 maj_stat, min_stat);
222 gss_release_name(&min_stat, &target_name);
223 return STOP;
225 free(out.s);
228 * Pass token obtained from second gss_init_sec_context() call.
230 gss_release_name(&min_stat, &target_name);
231 cp = memtob64(send_tok.value, send_tok.length);
232 gss_release_buffer(&min_stat, &send_tok);
233 snprintf(o, sizeof o, "%s\r\n", cp);
234 free(cp);
235 IMAP_OUT(o, 0, return STOP);
237 * First octet: bit-mask with protection mechanisms.
238 * Second to fourth octet: maximum message size in network byte order.
240 * This code currently does not care about the values.
242 imap_answer(mp, 1);
243 if (response_type != RESPONSE_CONT)
244 return STOP;
245 in.s = responded_text;
246 in.l = strlen(responded_text);
247 mime_fromb64(&in, &out, 0);
248 recv_tok.value = out.s;
249 recv_tok.length = out.l;
250 maj_stat = gss_unwrap(&min_stat, gss_context, &recv_tok,
251 &send_tok, &conf_state, NULL);
252 if (maj_stat != GSS_S_COMPLETE) {
253 imap_gss_error("unwrapping data", maj_stat, min_stat);
254 return STOP;
256 free(out.s);
258 * First octet: bit-mask with protection mechanisms (1 = no protection
259 * mechanism).
260 * Second to fourth octet: maximum message size in network byte order.
261 * Fifth and following octets: user name string.
263 o[0] = 1;
264 o[1] = 0;
265 o[2] = o[3] = 0377;
266 snprintf(&o[4], sizeof o - 4, "%s", user);
267 send_tok.value = o;
268 send_tok.length = strlen(&o[4]) + 5;
269 maj_stat = gss_wrap(&min_stat, gss_context, 0, GSS_C_QOP_DEFAULT,
270 &send_tok, &conf_state, &recv_tok);
271 if (maj_stat != GSS_S_COMPLETE) {
272 imap_gss_error("wrapping data", maj_stat, min_stat);
273 return STOP;
275 cp = memtob64(recv_tok.value, recv_tok.length);
276 snprintf(o, sizeof o, "%s\r\n", cp);
277 free(cp);
278 IMAP_OUT(o, MB_COMD, return STOP);
279 while (mp->mb_active & MB_COMD)
280 ok = imap_answer(mp, 1);
281 gss_delete_sec_context(&min_stat, &gss_context, &recv_tok);
282 gss_release_buffer(&min_stat, &recv_tok);
283 return ok;
286 #endif /* USE_GSSAPI */