1 /*
2  * e-source-security.c
3  *
4  * This library is free software: you can redistribute it and/or modify it
5  * under the terms of the GNU Lesser General Public License as published by
6  * the Free Software Foundation.
7  *
8  * This library is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
11  * for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this library. If not, see <http://www.gnu.org/licenses/>.
15  *
16  */
17 
18 /**
19  * SECTION: e-source-security
20  * @include: libedataserver/libedataserver.h
21  * @short_description: #ESource extension for security settings
22  *
23  * The #ESourceSecurity extension tracks settings for establishing a
24  * secure connection with a remote server.
25  *
26  * Access the extension as follows:
27  *
28  * |[
29  *   #include <libedataserver/libedataserver.h>
30  *
31  *   ESourceSecurity *extension;
32  *
33  *   extension = e_source_get_extension (source, E_SOURCE_EXTENSION_SECURITY);
34  * ]|
35  **/
36 
37 #include "e-source-security.h"
38 
39 #include <libedataserver/e-data-server-util.h>
40 
41 #define SECURE_METHOD "tls"
42 
43 struct _ESourceSecurityPrivate {
44 	gchar *method;
45 };
46 
47 enum {
48 	PROP_0,
49 	PROP_METHOD,
50 	PROP_SECURE
51 };
52 
G_DEFINE_TYPE_WITH_PRIVATE(ESourceSecurity,e_source_security,E_TYPE_SOURCE_EXTENSION)53 G_DEFINE_TYPE_WITH_PRIVATE (
54 	ESourceSecurity,
55 	e_source_security,
56 	E_TYPE_SOURCE_EXTENSION)
57 
58 static void
59 source_security_set_property (GObject *object,
60                               guint property_id,
61                               const GValue *value,
62                               GParamSpec *pspec)
63 {
64 	switch (property_id) {
65 		case PROP_METHOD:
66 			e_source_security_set_method (
67 				E_SOURCE_SECURITY (object),
68 				g_value_get_string (value));
69 			return;
70 
71 		case PROP_SECURE:
72 			e_source_security_set_secure (
73 				E_SOURCE_SECURITY (object),
74 				g_value_get_boolean (value));
75 			return;
76 	}
77 
78 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
79 }
80 
81 static void
source_security_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)82 source_security_get_property (GObject *object,
83                               guint property_id,
84                               GValue *value,
85                               GParamSpec *pspec)
86 {
87 	switch (property_id) {
88 		case PROP_METHOD:
89 			g_value_take_string (
90 				value,
91 				e_source_security_dup_method (
92 				E_SOURCE_SECURITY (object)));
93 			return;
94 
95 		case PROP_SECURE:
96 			g_value_set_boolean (
97 				value,
98 				e_source_security_get_secure (
99 				E_SOURCE_SECURITY (object)));
100 			return;
101 	}
102 
103 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
104 }
105 
106 static void
source_security_finalize(GObject * object)107 source_security_finalize (GObject *object)
108 {
109 	ESourceSecurityPrivate *priv;
110 
111 	priv = E_SOURCE_SECURITY (object)->priv;
112 
113 	g_free (priv->method);
114 
115 	/* Chain up to parent's finalize() method. */
116 	G_OBJECT_CLASS (e_source_security_parent_class)->finalize (object);
117 }
118 
119 static void
e_source_security_class_init(ESourceSecurityClass * class)120 e_source_security_class_init (ESourceSecurityClass *class)
121 {
122 	GObjectClass *object_class;
123 	ESourceExtensionClass *extension_class;
124 
125 	object_class = G_OBJECT_CLASS (class);
126 	object_class->set_property = source_security_set_property;
127 	object_class->get_property = source_security_get_property;
128 	object_class->finalize = source_security_finalize;
129 
130 	extension_class = E_SOURCE_EXTENSION_CLASS (class);
131 	extension_class->name = E_SOURCE_EXTENSION_SECURITY;
132 
133 	g_object_class_install_property (
134 		object_class,
135 		PROP_METHOD,
136 		g_param_spec_string (
137 			"method",
138 			"Method",
139 			"Security method",
140 			"none",
141 			G_PARAM_READWRITE |
142 			G_PARAM_CONSTRUCT |
143 			G_PARAM_EXPLICIT_NOTIFY |
144 			G_PARAM_STATIC_STRINGS |
145 			E_SOURCE_PARAM_SETTING));
146 
147 	g_object_class_install_property (
148 		object_class,
149 		PROP_SECURE,
150 		g_param_spec_boolean (
151 			"secure",
152 			"Secure",
153 			"Secure the network connection",
154 			FALSE,
155 			G_PARAM_READWRITE |
156 			G_PARAM_EXPLICIT_NOTIFY |
157 			G_PARAM_STATIC_STRINGS));
158 }
159 
160 static void
e_source_security_init(ESourceSecurity * extension)161 e_source_security_init (ESourceSecurity *extension)
162 {
163 	extension->priv = e_source_security_get_instance_private (extension);
164 }
165 
166 /**
167  * e_source_security_get_method:
168  * @extension: an #ESourceSecurity
169  *
170  * Returns the method used to establish a secure network connection to a
171  * remote account.  There are no pre-defined method names; backends are
172  * free to set this however they wish.  If a secure connection is not
173  * desired, the convention is to set #ESourceSecurity:method to "none".
174  *
175  * Returns: the method used to establish a secure network connection
176  *
177  * Since: 3.6
178  **/
179 const gchar *
e_source_security_get_method(ESourceSecurity * extension)180 e_source_security_get_method (ESourceSecurity *extension)
181 {
182 	g_return_val_if_fail (E_IS_SOURCE_SECURITY (extension), NULL);
183 
184 	return extension->priv->method;
185 }
186 
187 /**
188  * e_source_security_dup_method:
189  * @extension: an #ESourceSecurity
190  *
191  * Thread-safe variation of e_source_security_get_method().
192  * Use this function when accessing @extension from multiple threads.
193  *
194  * The returned string should be freed with g_free() when no longer needed.
195  *
196  * Returns: a newly-allocated copy of #ESourceSecurity:method
197  *
198  * Since: 3.6
199  **/
200 gchar *
e_source_security_dup_method(ESourceSecurity * extension)201 e_source_security_dup_method (ESourceSecurity *extension)
202 {
203 	const gchar *protected;
204 	gchar *duplicate;
205 
206 	g_return_val_if_fail (E_IS_SOURCE_SECURITY (extension), NULL);
207 
208 	e_source_extension_property_lock (E_SOURCE_EXTENSION (extension));
209 
210 	protected = e_source_security_get_method (extension);
211 	duplicate = g_strdup (protected);
212 
213 	e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension));
214 
215 	return duplicate;
216 }
217 
218 /**
219  * e_source_security_set_method:
220  * @extension: an #ESourceSecurity
221  * @method: (nullable): security method, or %NULL
222  *
223  * Sets the method used to establish a secure network connection to a
224  * remote account.  There are no pre-defined method names; backends are
225  * free to set this however they wish.  If a secure connection is not
226  * desired, the convention is to set #ESourceSecurity:method to "none".
227  * In keeping with that convention, #ESourceSecurity:method will be set
228  * to "none" if @method is %NULL or an empty string.
229  *
230  * Since: 3.6
231  **/
232 void
e_source_security_set_method(ESourceSecurity * extension,const gchar * method)233 e_source_security_set_method (ESourceSecurity *extension,
234                               const gchar *method)
235 {
236 	GObject *object;
237 
238 	g_return_if_fail (E_IS_SOURCE_SECURITY (extension));
239 
240 	e_source_extension_property_lock (E_SOURCE_EXTENSION (extension));
241 
242 	if (e_util_strcmp0 (extension->priv->method, method) == 0) {
243 		e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension));
244 		return;
245 	}
246 
247 	g_free (extension->priv->method);
248 	extension->priv->method = e_util_strdup_strip (method);
249 
250 	if (extension->priv->method == NULL)
251 		extension->priv->method = g_strdup ("none");
252 
253 	e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension));
254 
255 	object = G_OBJECT (extension);
256 	g_object_freeze_notify (object);
257 	g_object_notify (object, "method");
258 	g_object_notify (object, "secure");
259 	g_object_thaw_notify (object);
260 }
261 
262 /**
263  * e_source_security_get_secure:
264  * @extension: an #ESourceSecurity
265  *
266  * This is a convenience function which returns whether a secure network
267  * connection is desired, regardless of the method used.  This relies on
268  * the convention of setting #ESourceSecurity:method to "none" when a
269  * secure network connection is <emphasis>not</emphasis> desired.
270  *
271  * Returns: whether a secure network connection is desired
272  *
273  * Since: 3.6
274  **/
275 gboolean
e_source_security_get_secure(ESourceSecurity * extension)276 e_source_security_get_secure (ESourceSecurity *extension)
277 {
278 	const gchar *method;
279 
280 	g_return_val_if_fail (E_IS_SOURCE_SECURITY (extension), FALSE);
281 
282 	method = e_source_security_get_method (extension);
283 	g_return_val_if_fail (method != NULL, FALSE);
284 
285 	return (g_strcmp0 (method, "none") != 0);
286 }
287 
288 /**
289  * e_source_security_set_secure:
290  * @extension: an #ESourceSecurity
291  * @secure: whether a secure network connection is desired
292  *
293  * This function provides a simpler way to set #ESourceSecurity:method
294  * when using a secure network connection is a yes or no option and the
295  * exact method name is unimportant.  If @secure is %FALSE, the
296  * #ESourceSecurity:method property is set to "none".  If @secure is
297  * %TRUE, the function assumes the backend will use Transport Layer
298  * Security and sets the #ESourceSecurity:method property to "tls".
299  *
300  * Since: 3.6
301  **/
302 void
e_source_security_set_secure(ESourceSecurity * extension,gboolean secure)303 e_source_security_set_secure (ESourceSecurity *extension,
304                               gboolean secure)
305 {
306 	const gchar *method;
307 
308 	g_return_if_fail (E_IS_SOURCE_SECURITY (extension));
309 
310 	method = secure ? SECURE_METHOD : "none";
311 	e_source_security_set_method (extension, method);
312 }
313