1 /********************************************************************\
2 * BitlBee -- An IRC to other IM-networks gateway *
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"
30 #define SECURITY_WIN32
36 static gboolean initialized
= FALSE
;
42 ssl_input_function func
;
45 CredHandle cred
; /* SSL credentials */
46 CtxtHandle context
; /* SSL context */
47 SecPkgContext_StreamSizes sizes
;
51 char *pending_raw_data
;
52 gsize pending_raw_data_len
;
54 gsize pending_data_len
;
57 static void ssl_connected(gpointer
, gint
, GaimInputCondition
);
59 void sspi_global_init(void)
64 void sspi_global_deinit(void)
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
);
77 conn
->host
= g_strdup(host
);
89 atexit(sspi_global_deinit
);
95 static void ssl_connected(gpointer _conn
, gint fd
, GaimInputCondition cond
)
97 struct scd
*conn
= _conn
;
98 SCHANNEL_CRED ssl_cred
;
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
;
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
, ×tamp
);
116 if (st
!= SEC_E_OK
) {
117 conn
->func(conn
->data
, NULL
, cond
);
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
, ×tamp
);
135 if (obuf
[0].pvBuffer
&& obuf
[0].cbBuffer
) {
136 /* FIXME: Check return value */
137 send(conn
->fd
, obuf
[0].pvBuffer
, obuf
[0].cbBuffer
, 0);
141 case SEC_I_INCOMPLETE_CREDENTIALS
:
143 case SEC_I_CONTINUE_NEEDED
:
145 case SEC_E_INCOMPLETE_MESSAGE
:
151 QueryContextAttributes(&conn
->context
, SECPKG_ATTR_STREAM_SIZES
, &conn
->sizes
);
154 conn
->func(conn
->data
, conn
, cond
);
157 int ssl_read(void *conn
, char *retdata
, int len
)
159 struct scd
*scd
= conn
;
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
;
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
) {
186 for (i
= 0; i
< 4; i
++) {
187 if (buf
[i
].BufferType
== SECBUFFER_DATA
) {
188 memcpy(retdata
, buf
[i
].pvBuffer
, len
);
197 int ssl_write(void *conn
, const char *userdata
, int len
)
199 struct scd
*scd
= conn
;
205 msg
.ulVersion
= SECBUFFER_VERSION
;
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);
235 void ssl_disconnect(void *conn
)
237 struct scd
*scd
= conn
;
243 dw
= SCHANNEL_SHUTDOWN
;
244 buf
.cbBuffer
= sizeof(dw
);
245 buf
.BufferType
= SECBUFFER_TOKEN
;
248 msg
.ulVersion
= SECBUFFER_VERSION
;
252 SECURITY_STATUS st
= ApplyControlToken(&scd
->context
, &msg
);
254 if (st
!= SEC_E_OK
) {
258 /* FIXME: call InitializeSecurityContext(Schannel), passing
261 DeleteSecurityContext(&scd
->context
);
263 FreeCredentialsHandle(&scd
->cred
);
265 closesocket(scd
->fd
);
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 */