qulogic/pidgin
Clone
Summary
Browse
Changes
Graph
Use g_slist_free_full and g_list_free_full in a few places.
2014-01-20, Mark Doliner
2561402bb3fd
Use g_slist_free_full and g_list_free_full in a few places.
/**
* @file sslconn.c SSL API
* @ingroup core
*/
/* purple
*
* Purple is the legal property of its developers, whose names are too numerous
* to list here. Please refer to the COPYRIGHT file distributed with this
* source distribution.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
*/
#define _PURPLE_SSLCONN_C_
#include
"internal.h"
#include
"certificate.h"
#include
"debug.h"
#include
"request.h"
#include
"sslconn.h"
static
gboolean
_ssl_initialized
=
FALSE
;
static
PurpleSslOps
*
_ssl_ops
=
NULL
;
static
gboolean
ssl_init
(
void
)
{
PurplePlugin
*
plugin
;
PurpleSslOps
*
ops
;
if
(
_ssl_initialized
)
return
FALSE
;
plugin
=
purple_plugins_find_with_id
(
"core-ssl"
);
if
(
plugin
!=
NULL
&&
!
purple_plugin_is_loaded
(
plugin
))
purple_plugin_load
(
plugin
);
ops
=
purple_ssl_get_ops
();
if
((
ops
==
NULL
)
||
(
ops
->
init
==
NULL
)
||
(
ops
->
uninit
==
NULL
)
||
(
ops
->
connectfunc
==
NULL
)
||
(
ops
->
close
==
NULL
)
||
(
ops
->
read
==
NULL
)
||
(
ops
->
write
==
NULL
))
{
return
FALSE
;
}
return
(
_ssl_initialized
=
ops
->
init
());
}
gboolean
purple_ssl_is_supported
(
void
)
{
#ifdef HAVE_SSL
ssl_init
();
return
(
purple_ssl_get_ops
()
!=
NULL
);
#else
return
FALSE
;
#endif
}
static
void
purple_ssl_connect_cb
(
gpointer
data
,
gint
source
,
const
gchar
*
error_message
)
{
PurpleSslConnection
*
gsc
;
PurpleSslOps
*
ops
;
gsc
=
data
;
gsc
->
connect_data
=
NULL
;
if
(
source
<
0
)
{
if
(
gsc
->
error_cb
!=
NULL
)
gsc
->
error_cb
(
gsc
,
PURPLE_SSL_CONNECT_FAILED
,
gsc
->
connect_cb_data
);
purple_ssl_close
(
gsc
);
return
;
}
gsc
->
fd
=
source
;
ops
=
purple_ssl_get_ops
();
ops
->
connectfunc
(
gsc
);
}
PurpleSslConnection
*
purple_ssl_connect
(
PurpleAccount
*
account
,
const
char
*
host
,
int
port
,
PurpleSslInputFunction
func
,
PurpleSslErrorFunction
error_func
,
void
*
data
)
{
return
purple_ssl_connect_with_ssl_cn
(
account
,
host
,
port
,
func
,
error_func
,
NULL
,
data
);
}
PurpleSslConnection
*
purple_ssl_connect_with_ssl_cn
(
PurpleAccount
*
account
,
const
char
*
host
,
int
port
,
PurpleSslInputFunction
func
,
PurpleSslErrorFunction
error_func
,
const
char
*
ssl_cn
,
void
*
data
)
{
PurpleSslConnection
*
gsc
;
g_return_val_if_fail
(
host
!=
NULL
,
NULL
);
g_return_val_if_fail
(
port
!=
0
&&
port
!=
-1
,
NULL
);
g_return_val_if_fail
(
func
!=
NULL
,
NULL
);
g_return_val_if_fail
(
purple_ssl_is_supported
(),
NULL
);
if
(
!
_ssl_initialized
)
{
if
(
!
ssl_init
())
return
NULL
;
}
gsc
=
g_new0
(
PurpleSslConnection
,
1
);
gsc
->
fd
=
-1
;
gsc
->
host
=
ssl_cn
?
g_strdup
(
ssl_cn
)
:
g_strdup
(
host
);
gsc
->
port
=
port
;
gsc
->
connect_cb_data
=
data
;
gsc
->
connect_cb
=
func
;
gsc
->
error_cb
=
error_func
;
/* TODO: Move this elsewhere */
gsc
->
verifier
=
purple_certificate_find_verifier
(
"x509"
,
"tls_cached"
);
gsc
->
connect_data
=
purple_proxy_connect
(
NULL
,
account
,
host
,
port
,
purple_ssl_connect_cb
,
gsc
);
if
(
gsc
->
connect_data
==
NULL
)
{
g_free
(
gsc
->
host
);
g_free
(
gsc
);
return
NULL
;
}
return
(
PurpleSslConnection
*
)
gsc
;
}
static
void
recv_cb
(
gpointer
data
,
gint
source
,
PurpleInputCondition
cond
)
{
PurpleSslConnection
*
gsc
=
data
;
gsc
->
recv_cb
(
gsc
->
recv_cb_data
,
gsc
,
cond
);
}
void
purple_ssl_input_add
(
PurpleSslConnection
*
gsc
,
PurpleSslInputFunction
func
,
void
*
data
)
{
g_return_if_fail
(
func
!=
NULL
);
g_return_if_fail
(
purple_ssl_is_supported
());
purple_ssl_input_remove
(
gsc
);
gsc
->
recv_cb_data
=
data
;
gsc
->
recv_cb
=
func
;
gsc
->
inpa
=
purple_input_add
(
gsc
->
fd
,
PURPLE_INPUT_READ
,
recv_cb
,
gsc
);
}
void
purple_ssl_input_remove
(
PurpleSslConnection
*
gsc
)
{
if
(
gsc
->
inpa
>
0
)
{
purple_input_remove
(
gsc
->
inpa
);
gsc
->
inpa
=
0
;
}
}
const
gchar
*
purple_ssl_strerror
(
PurpleSslErrorType
error
)
{
switch
(
error
)
{
case
PURPLE_SSL_CONNECT_FAILED
:
return
_
(
"SSL Connection Failed"
);
case
PURPLE_SSL_HANDSHAKE_FAILED
:
return
_
(
"SSL Handshake Failed"
);
case
PURPLE_SSL_CERTIFICATE_INVALID
:
return
_
(
"SSL peer presented an invalid certificate"
);
default
:
purple_debug_warning
(
"sslconn"
,
"Unknown SSL error code %d
\n
"
,
error
);
return
_
(
"Unknown SSL error"
);
}
}
PurpleSslConnection
*
purple_ssl_connect_with_host_fd
(
PurpleAccount
*
account
,
int
fd
,
PurpleSslInputFunction
func
,
PurpleSslErrorFunction
error_func
,
const
char
*
host
,
void
*
data
)
{
PurpleSslConnection
*
gsc
;
PurpleSslOps
*
ops
;
g_return_val_if_fail
(
fd
!=
-1
,
NULL
);
g_return_val_if_fail
(
func
!=
NULL
,
NULL
);
g_return_val_if_fail
(
purple_ssl_is_supported
(),
NULL
);
if
(
!
_ssl_initialized
)
{
if
(
!
ssl_init
())
return
NULL
;
}
gsc
=
g_new0
(
PurpleSslConnection
,
1
);
gsc
->
connect_cb_data
=
data
;
gsc
->
connect_cb
=
func
;
gsc
->
error_cb
=
error_func
;
gsc
->
fd
=
fd
;
if
(
host
)
gsc
->
host
=
g_strdup
(
host
);
/* TODO: Move this elsewhere */
gsc
->
verifier
=
purple_certificate_find_verifier
(
"x509"
,
"tls_cached"
);
ops
=
purple_ssl_get_ops
();
ops
->
connectfunc
(
gsc
);
return
(
PurpleSslConnection
*
)
gsc
;
}
void
purple_ssl_close
(
PurpleSslConnection
*
gsc
)
{
PurpleSslOps
*
ops
;
g_return_if_fail
(
gsc
!=
NULL
);
purple_request_close_with_handle
(
gsc
);
purple_notify_close_with_handle
(
gsc
);
ops
=
purple_ssl_get_ops
();
(
ops
->
close
)(
gsc
);
if
(
gsc
->
connect_data
!=
NULL
)
purple_proxy_connect_cancel
(
gsc
->
connect_data
);
if
(
gsc
->
inpa
>
0
)
purple_input_remove
(
gsc
->
inpa
);
if
(
gsc
->
fd
>=
0
)
close
(
gsc
->
fd
);
g_free
(
gsc
->
host
);
g_free
(
gsc
);
}
size_t
purple_ssl_read
(
PurpleSslConnection
*
gsc
,
void
*
data
,
size_t
len
)
{
PurpleSslOps
*
ops
;
g_return_val_if_fail
(
gsc
!=
NULL
,
0
);
g_return_val_if_fail
(
data
!=
NULL
,
0
);
g_return_val_if_fail
(
len
>
0
,
0
);
ops
=
purple_ssl_get_ops
();
return
(
ops
->
read
)(
gsc
,
data
,
len
);
}
size_t
purple_ssl_write
(
PurpleSslConnection
*
gsc
,
const
void
*
data
,
size_t
len
)
{
PurpleSslOps
*
ops
;
g_return_val_if_fail
(
gsc
!=
NULL
,
0
);
g_return_val_if_fail
(
data
!=
NULL
,
0
);
g_return_val_if_fail
(
len
>
0
,
0
);
ops
=
purple_ssl_get_ops
();
return
(
ops
->
write
)(
gsc
,
data
,
len
);
}
GList
*
purple_ssl_get_peer_certificates
(
PurpleSslConnection
*
gsc
)
{
PurpleSslOps
*
ops
;
g_return_val_if_fail
(
gsc
!=
NULL
,
NULL
);
ops
=
purple_ssl_get_ops
();
return
(
ops
->
get_peer_certificates
)(
gsc
);
}
void
purple_ssl_set_ops
(
PurpleSslOps
*
ops
)
{
_ssl_ops
=
ops
;
}
PurpleSslOps
*
purple_ssl_get_ops
(
void
)
{
return
_ssl_ops
;
}
void
purple_ssl_init
(
void
)
{
/* Although purple_ssl_is_supported will do the initialization on
command, SSL plugins tend to register CertificateSchemes as well
as providing SSL ops. */
if
(
!
ssl_init
())
{
purple_debug_error
(
"sslconn"
,
"Unable to initialize SSL.
\n
"
);
}
}
void
purple_ssl_uninit
(
void
)
{
PurpleSslOps
*
ops
;
if
(
!
_ssl_initialized
)
return
;
ops
=
purple_ssl_get_ops
();
ops
->
uninit
();
_ssl_initialized
=
FALSE
;
}