GCC Code Coverage Report


Directory: ./
File: panels/printers/pp-samba.c
Date: 2024-05-03 09:46:52
Exec Total Coverage
Lines: 0 152 0.0%
Functions: 0 16 0.0%
Branches: 0 85 0.0%

Line Branch Exec Source
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2 *
3 * Copyright 2012 - 2013 Red Hat, Inc,
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, see <http://www.gnu.org/licenses/>.
17 *
18 * Author: Marek Kasik <mkasik@redhat.com>
19 */
20
21 #include "pp-samba.h"
22
23 #include "config.h"
24
25 #include <glib/gi18n.h>
26 #include <libsmbclient.h>
27 #include <errno.h>
28
29 #define POLL_DELAY 100000
30
31 struct _PpSamba
32 {
33 PpHost parent_instance;
34
35 /* Auth info */
36 gchar *username;
37 gchar *password;
38 gboolean waiting;
39 };
40
41 G_DEFINE_TYPE (PpSamba, pp_samba, PP_TYPE_HOST);
42
43 static void
44 pp_samba_finalize (GObject *object)
45 {
46 PpSamba *self = PP_SAMBA (object);
47
48 g_clear_pointer (&self->username, g_free);
49 g_clear_pointer (&self->password, g_free);
50
51 G_OBJECT_CLASS (pp_samba_parent_class)->finalize (object);
52 }
53
54 static void
55 pp_samba_class_init (PpSambaClass *klass)
56 {
57 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
58
59 gobject_class->finalize = pp_samba_finalize;
60 }
61
62 static void
63 pp_samba_init (PpSamba *samba)
64 {
65 }
66
67 PpSamba *
68 pp_samba_new (const gchar *hostname)
69 {
70 return g_object_new (PP_TYPE_SAMBA,
71 "hostname", hostname,
72 NULL);
73 }
74
75 typedef struct
76 {
77 PpSamba *samba;
78 GPtrArray *devices;
79 GMainContext *context;
80 gboolean auth_if_needed;
81 gboolean hostname_set;
82 gboolean cancelled;
83 } SMBData;
84
85 static void
86 smb_data_free (SMBData *data)
87 {
88 if (data)
89 {
90 g_ptr_array_unref (data->devices);
91
92 g_free (data);
93 }
94 }
95
96 static gboolean
97 get_auth_info (gpointer user_data)
98 {
99 SMBData *data = (SMBData *) user_data;
100 PpSamba *samba = PP_SAMBA (data->samba);
101
102 g_signal_emit_by_name (samba, "authentication-required");
103
104 return FALSE;
105 }
106
107 void
108 pp_samba_set_auth_info (PpSamba *samba,
109 const gchar *username,
110 const gchar *password)
111 {
112 g_free (samba->username);
113 if ((username != NULL) && (username[0] != '\0'))
114 samba->username = g_strdup (username);
115 else
116 samba->username = NULL;
117
118 g_free (samba->password);
119 if ((password != NULL) && (password[0] != '\0'))
120 samba->password = g_strdup (password);
121 else
122 samba->password = NULL;
123
124 samba->waiting = FALSE;
125 }
126
127 static void
128 auth_fn (SMBCCTX *smb_context,
129 const char *server,
130 const char *share,
131 char *workgroup,
132 int wgmaxlen,
133 char *username,
134 int unmaxlen,
135 char *password,
136 int pwmaxlen)
137 {
138 PpSamba *samba;
139 g_autoptr(GSource) source = NULL;
140 SMBData *data;
141
142 data = (SMBData *) smbc_getOptionUserData (smb_context);
143 samba = data->samba;
144
145 if (!data->cancelled)
146 {
147 samba->username = g_strdup (username);
148 samba->password = g_strdup (password);
149
150 source = g_idle_source_new ();
151 g_source_set_callback (source,
152 get_auth_info,
153 data,
154 NULL);
155 g_source_attach (source, data->context);
156
157 samba->waiting = TRUE;
158
159 /*
160 * smbclient needs to get authentication data
161 * from this synchronous callback so we are blocking
162 * until we get them
163 */
164 while (samba->waiting)
165 {
166 g_usleep (POLL_DELAY);
167 }
168
169 /* Samba tries to call the auth_fn again if we just set the values
170 * to NULL when we want to cancel the authentication
171 */
172 if (samba->username == NULL && samba->password == NULL)
173 data->cancelled = TRUE;
174
175 if (samba->username != NULL)
176 {
177 if (g_strcmp0 (username, samba->username) != 0)
178 g_strlcpy (username, samba->username, unmaxlen);
179 }
180 else
181 {
182 username[0] = '\0';
183 }
184
185 if (samba->password != NULL)
186 {
187 if (g_strcmp0 (password, samba->password) != 0)
188 g_strlcpy (password, samba->password, pwmaxlen);
189 }
190 else
191 {
192 password[0] = '\0';
193 }
194
195 }
196 }
197
198 static void
199 anonymous_auth_fn (SMBCCTX *smb_context,
200 const char *server,
201 const char *share,
202 char *workgroup,
203 int wgmaxlen,
204 char *username,
205 int unmaxlen,
206 char *password,
207 int pwmaxlen)
208 {
209 username[0] = '\0';
210 password[0] = '\0';
211 }
212
213 static void
214 list_dir (SMBCCTX *smb_context,
215 const gchar *dirname,
216 const gchar *path,
217 GCancellable *cancellable,
218 SMBData *data)
219 {
220 struct smbc_dirent *dirent;
221 smbc_closedir_fn smbclient_closedir;
222 smbc_readdir_fn smbclient_readdir;
223 smbc_opendir_fn smbclient_opendir;
224 const gchar *host_name;
225 SMBCFILE *dir;
226
227 if (!g_cancellable_is_cancelled (cancellable))
228 {
229 smbclient_closedir = smbc_getFunctionClosedir (smb_context);
230 smbclient_readdir = smbc_getFunctionReaddir (smb_context);
231 smbclient_opendir = smbc_getFunctionOpendir (smb_context);
232
233 dir = smbclient_opendir (smb_context, dirname);
234 if (!dir && errno == EACCES)
235 {
236 if (g_str_has_prefix (dirname, "smb://"))
237 host_name = dirname + 6;
238 else
239 host_name = dirname;
240
241 if (data->auth_if_needed)
242 {
243 data->cancelled = FALSE;
244 smbc_setFunctionAuthDataWithContext (smb_context, auth_fn);
245 dir = smbclient_opendir (smb_context, dirname);
246 smbc_setFunctionAuthDataWithContext (smb_context, anonymous_auth_fn);
247
248 if (data->cancelled)
249 {
250 PpPrintDevice *device = g_object_new (PP_TYPE_PRINT_DEVICE,
251 "host-name", host_name,
252 "is-authenticated-server", TRUE,
253 NULL);
254 g_ptr_array_add (data->devices, device);
255
256 if (dir)
257 smbclient_closedir (smb_context, dir);
258 return;
259 }
260 }
261 else
262 {
263 PpPrintDevice *device = g_object_new (PP_TYPE_PRINT_DEVICE,
264 "host-name", host_name,
265 "is-authenticated-server", TRUE,
266 NULL);
267 g_ptr_array_add (data->devices, device);
268 }
269 }
270
271 while (dir && (dirent = smbclient_readdir (smb_context, dir)))
272 {
273 g_autofree gchar *subdirname = NULL;
274 g_autofree gchar *subpath = NULL;
275
276 if (dirent->smbc_type == SMBC_WORKGROUP)
277 {
278 subdirname = g_strdup_printf ("%s%s", dirname, dirent->name);
279 subpath = g_strdup_printf ("%s%s", path, dirent->name);
280 }
281
282 if (dirent->smbc_type == SMBC_SERVER)
283 {
284 subdirname = g_strdup_printf ("smb://%s", dirent->name);
285 subpath = g_strdup_printf ("%s//%s", path, dirent->name);
286 }
287
288 if (dirent->smbc_type == SMBC_PRINTER_SHARE)
289 {
290 g_autofree gchar *uri = NULL;
291 g_autofree gchar *device_name = NULL;
292 g_autofree gchar *device_uri = NULL;
293 PpPrintDevice *device;
294
295 uri = g_strdup_printf ("%s/%s", dirname, dirent->name);
296 device_uri = g_uri_escape_string (uri,
297 G_URI_RESERVED_CHARS_GENERIC_DELIMITERS
298 G_URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS,
299 FALSE);
300
301 device_name = g_strdup (dirent->name);
302 g_strcanon (device_name, ALLOWED_CHARACTERS, '-');
303
304 device = g_object_new (PP_TYPE_PRINT_DEVICE,
305 "device-uri", device_uri,
306 "is-network-device", TRUE,
307 "device-info", dirent->comment,
308 "device-name", device_name,
309 "acquisition-method", data->hostname_set ? ACQUISITION_METHOD_SAMBA_HOST : ACQUISITION_METHOD_SAMBA,
310 "device-location", path,
311 "host-name", dirname,
312 NULL);
313
314 g_ptr_array_add (data->devices, device);
315 }
316
317 if (subdirname)
318 {
319 list_dir (smb_context,
320 subdirname,
321 subpath,
322 cancellable,
323 data);
324 }
325 }
326
327 if (dir)
328 smbclient_closedir (smb_context, dir);
329 }
330 }
331
332 static void
333 _pp_samba_get_devices_thread (GTask *task,
334 gpointer source_object,
335 gpointer task_data,
336 GCancellable *cancellable)
337 {
338 static GMutex mutex;
339 SMBData *data = (SMBData *) task_data;
340 SMBCCTX *smb_context;
341
342 data->devices = g_ptr_array_new_with_free_func (g_object_unref);
343 data->samba = PP_SAMBA (source_object);
344
345 g_mutex_lock (&mutex);
346
347 smb_context = smbc_new_context ();
348 if (smb_context)
349 {
350 if (smbc_init_context (smb_context))
351 {
352 g_autofree gchar *hostname = NULL;
353 g_autofree gchar *dirname = NULL;
354 g_autofree gchar *path = NULL;
355
356 smbc_setOptionUserData (smb_context, data);
357
358 g_object_get (source_object, "hostname", &hostname, NULL);
359 if (hostname != NULL)
360 {
361 dirname = g_strdup_printf ("smb://%s", hostname);
362 path = g_strdup_printf ("//%s", hostname);
363 }
364 else
365 {
366 dirname = g_strdup_printf ("smb://");
367 path = g_strdup_printf ("//");
368 }
369
370 smbc_setFunctionAuthDataWithContext (smb_context, anonymous_auth_fn);
371 list_dir (smb_context, dirname, path, cancellable, data);
372 }
373
374 smbc_free_context (smb_context, 1);
375 }
376
377 g_mutex_unlock (&mutex);
378
379 g_task_return_pointer (task, g_ptr_array_ref (data->devices), (GDestroyNotify) g_ptr_array_unref);
380 }
381
382 void
383 pp_samba_get_devices_async (PpSamba *samba,
384 gboolean auth_if_needed,
385 GCancellable *cancellable,
386 GAsyncReadyCallback callback,
387 gpointer user_data)
388 {
389 g_autoptr(GTask) task = NULL;
390 SMBData *data;
391 g_autofree gchar *hostname = NULL;
392
393 g_object_get (G_OBJECT (samba), "hostname", &hostname, NULL);
394
395 task = g_task_new (samba, cancellable, callback, user_data);
396 data = g_new0 (SMBData, 1);
397 data->devices = NULL;
398 data->context = g_main_context_default ();
399 data->hostname_set = hostname != NULL;
400 data->auth_if_needed = auth_if_needed;
401
402 g_task_set_task_data (task, data, (GDestroyNotify) smb_data_free);
403 g_task_run_in_thread (task, _pp_samba_get_devices_thread);
404 }
405
406 GPtrArray *
407 pp_samba_get_devices_finish (PpSamba *samba,
408 GAsyncResult *res,
409 GError **error)
410 {
411 g_return_val_if_fail (g_task_is_valid (res, samba), NULL);
412 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
413 return g_task_propagate_pointer (G_TASK (res), error);
414 }
415