Scan media entities as well, not just url entities. This should expand more
[bitlbee.git] / lib / ssl_sspi.c
blobe14c451e1babb0e9724efef16b8ff7d212eb3529
1 /********************************************************************\
2 * BitlBee -- An IRC to other IM-networks gateway *
3 * *
4 * Copyright 2002-2004 Wilmer van der Gaast and others *
5 \********************************************************************/
7 /* SSL module - SSPI backend */
9 /* Copyright (C) 2005 Jelmer Vernooij <jelmer@samba.org> */
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 2 of the License, or
15 (at your option) any later version.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License with
23 the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
24 if not, write to the Free Software Foundation, Inc., 59 Temple Place,
25 Suite 330, Boston, MA 02111-1307 USA
28 #include "ssl_client.h"
29 #include <windows.h>
30 #define SECURITY_WIN32
31 #include <security.h>
32 #include <sspi.h>
33 #include <schannel.h>
34 #include "sock.h"
36 static gboolean initialized = FALSE;
37 int ssl_errno;
39 struct scd
41 int fd;
42 ssl_input_function func;
43 gpointer data;
44 gboolean established;
45 CredHandle cred; /* SSL credentials */
46 CtxtHandle context; /* SSL context */
47 SecPkgContext_StreamSizes sizes;
49 char *host;
51 char *pending_raw_data;
52 gsize pending_raw_data_len;
53 char *pending_data;
54 gsize pending_data_len;
57 static void ssl_connected(gpointer, gint, GaimInputCondition);
59 void sspi_global_init(void)
61 /* FIXME */
64 void sspi_global_deinit(void)
66 /* FIXME */
69 void *ssl_connect(char *host, int port, ssl_input_function func, gpointer data)
71 struct scd *conn = g_new0(struct scd, 1);
73 conn->fd = proxy_connect(host, port, ssl_connected, conn);
74 sock_make_nonblocking(conn->fd);
75 conn->func = func;
76 conn->data = data;
77 conn->host = g_strdup(host);
79 if (conn->fd < 0)
81 g_free(conn);
82 return NULL;
85 if (!initialized)
87 sspi_global_init();
88 initialized = TRUE;
89 atexit(sspi_global_deinit);
92 return conn;
95 static void ssl_connected(gpointer _conn, gint fd, GaimInputCondition cond)
97 struct scd *conn = _conn;
98 SCHANNEL_CRED ssl_cred;
99 TimeStamp timestamp;
100 SecBuffer ibuf[2],obuf[1];
101 SecBufferDesc ibufs,obufs;
102 ULONG req = ISC_REQ_REPLAY_DETECT | ISC_REQ_SEQUENCE_DETECT |
103 ISC_REQ_CONFIDENTIALITY | ISC_REQ_USE_SESSION_KEY |
104 ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM | ISC_REQ_EXTENDED_ERROR |
105 ISC_REQ_MANUAL_CRED_VALIDATION;
106 ULONG a;
107 gsize size = 0;
108 gchar *data = NULL;
110 memset(&ssl_cred, 0, sizeof(SCHANNEL_CRED));
111 ssl_cred.dwVersion = SCHANNEL_CRED_VERSION;
112 ssl_cred.grbitEnabledProtocols = SP_PROT_SSL3_CLIENT;
114 SECURITY_STATUS st = AcquireCredentialsHandle(NULL, UNISP_NAME, SECPKG_CRED_OUTBOUND, NULL, &ssl_cred, NULL, NULL, &conn->cred, &timestamp);
116 if (st != SEC_E_OK) {
117 conn->func(conn->data, NULL, cond);
118 return;
121 do {
122 /* initialize buffers */
123 ibuf[0].cbBuffer = size; ibuf[0].pvBuffer = data;
124 ibuf[1].cbBuffer = 0; ibuf[1].pvBuffer = NULL;
125 obuf[0].cbBuffer = 0; obuf[0].pvBuffer = NULL;
126 ibuf[0].BufferType = obuf[0].BufferType = SECBUFFER_TOKEN;
127 ibuf[1].BufferType = SECBUFFER_EMPTY;
129 /* initialize buffer descriptors */
130 ibufs.ulVersion = obufs.ulVersion = SECBUFFER_VERSION;
131 ibufs.cBuffers = 2; obufs.cBuffers = 1;
132 ibufs.pBuffers = ibuf; obufs.pBuffers = obuf;
134 st = InitializeSecurityContext(&conn->cred, size?&conn->context:NULL, conn->host, req, 0, SECURITY_NETWORK_DREP, size?&ibufs:NULL, 0, &conn->context, &obufs, &a, &timestamp);
135 if (obuf[0].pvBuffer && obuf[0].cbBuffer) {
136 /* FIXME: Check return value */
137 send(conn->fd, obuf[0].pvBuffer, obuf[0].cbBuffer, 0);
140 switch (st) {
141 case SEC_I_INCOMPLETE_CREDENTIALS:
142 break;
143 case SEC_I_CONTINUE_NEEDED:
144 break;
145 case SEC_E_INCOMPLETE_MESSAGE:
146 break;
147 case SEC_E_OK:
148 break;
151 QueryContextAttributes(&conn->context, SECPKG_ATTR_STREAM_SIZES, &conn->sizes);
152 } while (1);
154 conn->func(conn->data, conn, cond);
157 int ssl_read(void *conn, char *retdata, int len)
159 struct scd *scd = conn;
160 SecBufferDesc msg;
161 SecBuffer buf[4];
162 int ret = -1, i;
163 char *data = g_malloc(scd->sizes.cbHeader + scd->sizes.cbMaximumMessage + scd->sizes.cbTrailer);
165 /* FIXME: Try to read some data */
167 msg.ulVersion = SECBUFFER_VERSION;
168 msg.cBuffers = 4;
169 msg.pBuffers = buf;
171 buf[0].BufferType = SECBUFFER_DATA;
172 buf[0].cbBuffer = len;
173 buf[0].pvBuffer = data;
175 buf[1].BufferType = SECBUFFER_EMPTY;
176 buf[2].BufferType = SECBUFFER_EMPTY;
177 buf[3].BufferType = SECBUFFER_EMPTY;
179 SECURITY_STATUS st = DecryptMessage(&scd->context, &msg, 0, NULL);
181 if (st != SEC_E_OK) {
182 /* FIXME */
183 return -1;
186 for (i = 0; i < 4; i++) {
187 if (buf[i].BufferType == SECBUFFER_DATA) {
188 memcpy(retdata, buf[i].pvBuffer, len);
189 ret = len;
193 g_free(data);
194 return -1;
197 int ssl_write(void *conn, const char *userdata, int len)
199 struct scd *scd = conn;
200 SecBuffer buf[4];
201 SecBufferDesc msg;
202 char *data;
203 int ret;
205 msg.ulVersion = SECBUFFER_VERSION;
206 msg.cBuffers = 4;
207 msg.pBuffers = buf;
209 data = g_malloc(scd->sizes.cbHeader + scd->sizes.cbMaximumMessage + scd->sizes.cbTrailer);
210 memcpy(data + scd->sizes.cbHeader, userdata, len);
212 buf[0].BufferType = SECBUFFER_STREAM_HEADER;
213 buf[0].cbBuffer = scd->sizes.cbHeader;
214 buf[0].pvBuffer = data;
216 buf[1].BufferType = SECBUFFER_DATA;
217 buf[1].cbBuffer = len;
218 buf[1].pvBuffer = data + scd->sizes.cbHeader;
220 buf[2].BufferType = SECBUFFER_STREAM_TRAILER;
221 buf[2].cbBuffer = scd->sizes.cbTrailer;
222 buf[2].pvBuffer = data + scd->sizes.cbHeader + len;
223 buf[3].BufferType = SECBUFFER_EMPTY;
225 SECURITY_STATUS st = EncryptMessage(&scd->context, 0, &msg, 0);
227 ret = send(scd->fd, data,
228 buf[0].cbBuffer + buf[1].cbBuffer + buf[2].cbBuffer, 0);
230 g_free(data);
232 return ret;
235 void ssl_disconnect(void *conn)
237 struct scd *scd = conn;
239 SecBufferDesc msg;
240 SecBuffer buf;
241 DWORD dw;
243 dw = SCHANNEL_SHUTDOWN;
244 buf.cbBuffer = sizeof(dw);
245 buf.BufferType = SECBUFFER_TOKEN;
246 buf.pvBuffer = &dw;
248 msg.ulVersion = SECBUFFER_VERSION;
249 msg.cBuffers = 1;
250 msg.pBuffers = &buf;
252 SECURITY_STATUS st = ApplyControlToken(&scd->context, &msg);
254 if (st != SEC_E_OK) {
255 /* FIXME */
258 /* FIXME: call InitializeSecurityContext(Schannel), passing
259 * in empty buffers*/
261 DeleteSecurityContext(&scd->context);
263 FreeCredentialsHandle(&scd->cred);
265 closesocket(scd->fd);
266 g_free(scd->host);
267 g_free(scd);
270 int ssl_getfd(void *conn)
272 return ((struct scd*)conn)->fd;
275 GaimInputCondition ssl_getdirection( void *conn )
277 return B_EV_IO_WRITE; /* FIXME: or B_EV_IO_READ */