source: lib/ssl_sspi.c @ ff94563

Last change on this file since ff94563 was e046390, checked in by Wilmer van der Gaast <wilmer@…>, at 2009-10-10T23:25:54Z

Make purple use BitlBee's event handling API. Since the APIs never really
diverged too much this is fairly transparent. I did rename and redefine
GAIM_INPUT_* variables to really make it work without adding another stupid
layer in between.

One problem left, the new libpurple input API doesn't care about return
values. Fixing that in the next CL.

  • Property mode set to 100644
File size: 6.8 KB
Line 
1  /********************************************************************\
2  * BitlBee -- An IRC to other IM-networks gateway                     *
3  *                                                                    *
4  * Copyright 2002-2004 Wilmer van der Gaast and others                *
5  \********************************************************************/
6
7/* SSL module - SSPI backend */
8
9/* Copyright (C) 2005 Jelmer Vernooij <jelmer@samba.org> */
10
11/*
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.
16
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.
21
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
26*/
27
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"
35
36static gboolean initialized = FALSE;
37int ssl_errno;
38
39struct scd
40{
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;
48
49        char *host;
50
51        char *pending_raw_data;
52        gsize pending_raw_data_len;
53        char *pending_data;
54        gsize pending_data_len;
55};
56
57static void ssl_connected(gpointer, gint, GaimInputCondition);
58
59void sspi_global_init(void)
60{
61        /* FIXME */
62}
63
64void sspi_global_deinit(void)
65{
66        /* FIXME */
67}
68
69void *ssl_connect(char *host, int port, ssl_input_function func, gpointer data)
70{
71        struct scd *conn = g_new0(struct scd, 1);
72               
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);
78       
79        if (conn->fd < 0)
80        {
81                g_free(conn);
82                return NULL;
83        }
84       
85        if (!initialized)
86        {
87                sspi_global_init();
88                initialized = TRUE;
89                atexit(sspi_global_deinit);
90        }
91
92        return conn;
93}
94
95static void ssl_connected(gpointer _conn, gint fd, GaimInputCondition cond)
96{
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;
109
110        memset(&ssl_cred, 0, sizeof(SCHANNEL_CRED));
111        ssl_cred.dwVersion = SCHANNEL_CRED_VERSION;
112        ssl_cred.grbitEnabledProtocols = SP_PROT_SSL3_CLIENT;
113
114        SECURITY_STATUS st = AcquireCredentialsHandle(NULL, UNISP_NAME, SECPKG_CRED_OUTBOUND, NULL, &ssl_cred, NULL, NULL, &conn->cred, &timestamp);
115
116        if (st != SEC_E_OK) {
117                conn->func(conn->data, NULL, cond);
118                return;
119        }
120       
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;
128
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;
133
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);
138                }
139
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;
149                }
150       
151                QueryContextAttributes(&conn->context, SECPKG_ATTR_STREAM_SIZES, &conn->sizes);
152        } while (1);
153
154        conn->func(conn->data, conn, cond);
155}
156
157int ssl_read(void *conn, char *retdata, int len)
158{
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);
164
165        /* FIXME: Try to read some data */
166
167        msg.ulVersion = SECBUFFER_VERSION;
168        msg.cBuffers = 4;
169        msg.pBuffers = buf;
170       
171        buf[0].BufferType = SECBUFFER_DATA;
172        buf[0].cbBuffer = len;
173        buf[0].pvBuffer = data;
174
175        buf[1].BufferType = SECBUFFER_EMPTY;
176        buf[2].BufferType = SECBUFFER_EMPTY;
177        buf[3].BufferType = SECBUFFER_EMPTY;
178
179        SECURITY_STATUS st = DecryptMessage(&scd->context, &msg, 0, NULL);
180
181        if (st != SEC_E_OK) {
182                /* FIXME */
183                return -1;
184        }
185
186        for (i = 0; i < 4; i++) {
187                if (buf[i].BufferType == SECBUFFER_DATA) {
188                        memcpy(retdata, buf[i].pvBuffer, len);
189                        ret = len;
190                }       
191        }
192
193        g_free(data);
194        return -1;
195}
196
197int ssl_write(void *conn, const char *userdata, int len)
198{
199        struct scd *scd = conn;
200        SecBuffer buf[4];
201        SecBufferDesc msg;
202        char *data;
203        int ret;
204
205        msg.ulVersion = SECBUFFER_VERSION;
206        msg.cBuffers = 4;
207        msg.pBuffers = buf;
208
209        data = g_malloc(scd->sizes.cbHeader + scd->sizes.cbMaximumMessage + scd->sizes.cbTrailer);
210        memcpy(data + scd->sizes.cbHeader, userdata, len);
211
212        buf[0].BufferType = SECBUFFER_STREAM_HEADER;
213        buf[0].cbBuffer = scd->sizes.cbHeader;
214        buf[0].pvBuffer = data;
215
216        buf[1].BufferType = SECBUFFER_DATA;
217        buf[1].cbBuffer = len;
218        buf[1].pvBuffer = data + scd->sizes.cbHeader;
219
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;
224
225        SECURITY_STATUS st = EncryptMessage(&scd->context, 0, &msg, 0);
226
227        ret = send(scd->fd, data, 
228                                buf[0].cbBuffer + buf[1].cbBuffer + buf[2].cbBuffer, 0);
229
230        g_free(data);
231
232        return ret;
233}
234
235void ssl_disconnect(void *conn)
236{
237        struct scd *scd = conn;
238
239        SecBufferDesc msg;
240        SecBuffer buf;
241        DWORD dw;
242
243        dw = SCHANNEL_SHUTDOWN;
244        buf.cbBuffer = sizeof(dw);
245        buf.BufferType = SECBUFFER_TOKEN;
246        buf.pvBuffer = &dw;
247       
248        msg.ulVersion = SECBUFFER_VERSION;
249        msg.cBuffers = 1;
250        msg.pBuffers = &buf;
251
252        SECURITY_STATUS st = ApplyControlToken(&scd->context, &msg);
253
254        if (st != SEC_E_OK) {
255                /* FIXME */
256        }
257       
258        /* FIXME: call InitializeSecurityContext(Schannel), passing
259         * in empty buffers*/
260
261        DeleteSecurityContext(&scd->context);
262
263        FreeCredentialsHandle(&scd->cred);
264
265        closesocket(scd->fd);
266        g_free(scd->host);
267        g_free(scd);
268}
269
270int ssl_getfd(void *conn)
271{
272        return ((struct scd*)conn)->fd;
273}
274
275GaimInputCondition ssl_getdirection( void *conn )
276{
277        return B_EV_IO_WRITE; /* FIXME: or B_EV_IO_READ */
278}
Note: See TracBrowser for help on using the repository browser.