Remmina - The GTK+ Remote Desktop Client  v1.4.33
Remmina is a remote desktop client written in GTK+, aiming to be useful for system administrators and travellers, who need to work with lots of remote computers in front of either large monitors or tiny netbooks. Remmina supports multiple network protocols in an integrated and consistent user interface. Currently RDP, VNC, NX, XDMCP and SSH are supported.
remmina_unlock.c
Go to the documentation of this file.
1 /*
2  * Remmina - The GTK+ Remote Desktop Client
3  * Copyright (C) 2016-2023 Antenore Gatta, Giovanni Panozzo
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, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  *
20  * In addition, as a special exception, the copyright holders give
21  * permission to link the code of portions of this program with the
22  * OpenSSL library under certain conditions as described in each
23  * individual source file, and distribute linked combinations
24  * including the two.
25  * You must obey the GNU General Public License in all respects
26  * for all of the code used other than OpenSSL. * If you modify
27  * file(s) with this exception, you may extend this exception to your
28  * version of the file(s), but you are not obligated to do so. * If you
29  * do not wish to do so, delete this exception statement from your
30  * version. * If you delete this exception statement from all source
31  * files in the program, then also delete it here.
32  *
33  */
34 
35 #include <stdlib.h>
36 
37 #include <glib/gi18n.h>
38 #include <glib.h>
39 #include <glib/gprintf.h>
40 
41 #include "config.h"
42 #include "remmina_sodium.h"
43 #include "remmina_pref.h"
44 #include "remmina_log.h"
45 #include "remmina_unlock.h"
46 #include "remmina_passwd.h"
47 #include "remmina_public.h"
49 
50 #if SODIUM_VERSION_INT >= 90200
52 #define GET_OBJ(object_name) gtk_builder_get_object(remmina_unlock_dialog->builder, object_name)
53 
54 GTimer *timer;
55 gboolean unlocked;
56 
58 {
59  TRACE_CALL(__func__);
60 
61  timer = g_timer_new();
62  REMMINA_DEBUG("Validity timer for Remmina password started");
63 }
64 
65 static void remmina_unlock_timer_reset(gpointer user_data)
66 {
67  TRACE_CALL(__func__);
68 
69  g_timer_reset(timer);
70  REMMINA_DEBUG("Validity timer for Remmina password reset");
71 }
72 
74 {
75  TRACE_CALL(__func__);
76 
77  g_timer_destroy(timer);
78  timer = NULL;
79 }
80 
81 static void remmina_unlock_unlock_clicked(GtkButton *btn, gpointer user_data)
82 {
83  TRACE_CALL(__func__);
84  //g_timer_reset(NULL);
85 
86  gchar *unlock_password;
87  const gchar *entry_passwd;
88  gint rc;
89 
90  unlock_password = remmina_pref_get_value("unlock_password");
91  entry_passwd = gtk_entry_get_text(remmina_unlock_dialog->entry_unlock);
92  rc = remmina_sodium_pwhash_str_verify(unlock_password, entry_passwd);
93  //REMMINA_DEBUG("remmina_sodium_pwhash_str_verify returned %i", rc);
94 
95  if (rc == 0) {
96  REMMINA_DEBUG("Password verified");
97  //unlocked = FALSE;
98  remmina_unlock_dialog->retval = TRUE;
99  } else {
100  REMMINA_WARNING ("The password is wrong. Reset it by editing the remmina.pref file by hand");
102  remmina_unlock_dialog->retval = FALSE;
103  }
104  gtk_dialog_response(remmina_unlock_dialog->dialog, GTK_RESPONSE_ACCEPT);
105 }
106 
107 static void remmina_unlock_cancel_clicked(GtkButton *btn, gpointer user_data)
108 {
109  TRACE_CALL(__func__);
110  gtk_dialog_response(remmina_unlock_dialog->dialog, GTK_RESPONSE_CANCEL);
111 }
112 
113 gint remmina_unlock_new(GtkWindow *parent)
114 {
115  TRACE_CALL(__func__);
116 
117  gdouble unlock_timeout;
118  gdouble elapsed = 0.0;
119  gboolean lock = FALSE;
120  gboolean rc;
121 
122  /* We don't have a timer, so this is the first time
123  * or the timer has been destroyed
124  */
125  if (timer == NULL) {
127  unlocked = FALSE;
128  }
129 
130  /* We have a timer, we get the elapsed time since its start */
131  if (timer != NULL)
132  elapsed = g_timer_elapsed(timer, NULL);
133 
134  /* We stop the timer while we enter the password) */
135  if (timer) g_timer_stop(timer);
136 
137  unlock_timeout = remmina_pref.unlock_timeout;
138  REMMINA_DEBUG ("unlock_timeout = %f", unlock_timeout);
139  REMMINA_DEBUG ("elapsed = %f", elapsed);
140  REMMINA_DEBUG ("INT unlock_timeout = %d", (int)unlock_timeout);
141  REMMINA_DEBUG ("INT elapsed = %d", (int)elapsed);
142  /* always LOCK and ask password */
143  if ((elapsed) && ((int)unlock_timeout - elapsed) <= 0) {
144  unlocked = FALSE;
146  }
147  /* We don't lock as it has been already requested */
148  //if (!unlocked && ((int)unlock_timeout - elapsed) > 0) unlocked = TRUE;
149 
150  REMMINA_DEBUG("Based on settings and current status, the unlocking dialog is set to %d", unlocked);
151 
152  if (unlocked) {
153  REMMINA_DEBUG ("No need to request a password");
154  rc = TRUE;
155  return rc;
156  } else {
157 
158  remmina_unlock_dialog = g_new0(RemminaUnlockDialog, 1);
159  remmina_unlock_dialog->retval = FALSE;
160 
161  remmina_unlock_dialog->builder = remmina_public_gtk_builder_new_from_resource("/org/remmina/Remmina/src/../data/ui/remmina_unlock.glade");
162  remmina_unlock_dialog->dialog = GTK_DIALOG(gtk_builder_get_object(remmina_unlock_dialog->builder, "RemminaUnlockDialog"));
163  if (parent)
164  gtk_window_set_transient_for(GTK_WINDOW(remmina_unlock_dialog->dialog), parent);
165 
166  remmina_unlock_dialog->entry_unlock = GTK_ENTRY(GET_OBJ("entry_unlock"));
167  gtk_entry_set_activates_default(GTK_ENTRY(remmina_unlock_dialog->entry_unlock), TRUE);
168  remmina_unlock_dialog->button_unlock = GTK_BUTTON(GET_OBJ("button_unlock"));
169  gtk_widget_set_can_default(GTK_WIDGET(remmina_unlock_dialog->button_unlock), TRUE);
170  gtk_widget_grab_default(GTK_WIDGET(remmina_unlock_dialog->button_unlock));
171  remmina_unlock_dialog->button_unlock_cancel = GTK_BUTTON(GET_OBJ("button_unlock_cancel"));
172 
173  g_signal_connect(remmina_unlock_dialog->button_unlock, "clicked",
174  G_CALLBACK(remmina_unlock_unlock_clicked), (gpointer)remmina_unlock_dialog);
175  g_signal_connect(remmina_unlock_dialog->button_unlock_cancel, "clicked",
176  G_CALLBACK(remmina_unlock_cancel_clicked), (gpointer)remmina_unlock_dialog);
177  g_signal_connect (remmina_unlock_dialog->dialog, "close",
178  G_CALLBACK (remmina_unlock_cancel_clicked), (gpointer)remmina_unlock_dialog);
179 
180  /* Connect signals */
181  gtk_builder_connect_signals(remmina_unlock_dialog->builder, NULL);
182 
183  g_object_set_data_full (G_OBJECT(remmina_unlock_dialog->dialog), "builder", remmina_unlock_dialog->builder, g_object_unref);
184 
185  gchar *unlock_password = NULL;
186  unlock_password = g_strdup(remmina_pref_get_value("unlock_password"));
187  //REMMINA_DEBUG ("Password from preferences is: %s", unlock_password);
188  if ((unlock_password == NULL) || (g_strcmp0(unlock_password, "") == 0)) {
189  if (remmina_passwd (GTK_WINDOW(remmina_unlock_dialog->dialog), &unlock_password)) {
190  //REMMINA_DEBUG ("Password is: %s", unlock_password);
191  remmina_pref_set_value("unlock_password", g_strdup(unlock_password));
192  remmina_unlock_dialog->retval = TRUE;
193  } else {
194  remmina_unlock_dialog->retval = FALSE;
195  }
196  }
197 
198  int result = GTK_RESPONSE_NONE;
199  if (g_strcmp0(unlock_password, "") != 0) {
200  result = gtk_dialog_run (GTK_DIALOG (remmina_unlock_dialog->dialog));
201  } else
202  remmina_unlock_dialog->retval = lock;
203 
204  switch (result)
205  {
206  case GTK_RESPONSE_ACCEPT:
207  if (!remmina_unlock_dialog->retval)
208  REMMINA_DEBUG ("Wrong password");
209  else {
210  REMMINA_DEBUG ("Correct password. Unlocking…");
211  unlocked = TRUE;
212  }
213  REMMINA_DEBUG ("retval: %d", remmina_unlock_dialog->retval);
214  break;
215  default:
216  //unlocked = FALSE;
217  remmina_unlock_dialog->retval = FALSE;
219  REMMINA_DEBUG ("Password not requested. Return value: %d", remmina_unlock_dialog->retval);
220  break;
221  }
222 
223  rc = remmina_unlock_dialog->retval;
224 
225  g_free(unlock_password), unlock_password = NULL;
226  gtk_widget_destroy(GTK_WIDGET(remmina_unlock_dialog->dialog));
227  remmina_unlock_dialog->dialog = NULL;
228  }
229  if (timer) g_timer_start(timer);
230  return(rc);
231 }
232 
233 #else
234 gint remmina_unlock_new(GtkWindow *parent)
235 {
236  return 1;
237 }
238 #endif
GtkBuilder * builder
static void remmina_unlock_cancel_clicked(GtkButton *btn, gpointer user_data)
GtkButton * button_unlock
gboolean remmina_passwd(GtkWindow *parent, gchar **unlock_password)
void remmina_pref_set_value(const gchar *key, const gchar *value)
gchar * remmina_pref_get_value(const gchar *key)
gint remmina_sodium_pwhash_str_verify(const char *key, const char *pass)
GTimer * timer
gint unlock_timeout
Definition: remmina_pref.h:193
GtkButton * button_unlock_cancel
static void remmina_unlock_unlock_clicked(GtkButton *btn, gpointer user_data)
static RemminaUnlockDialog * remmina_unlock_dialog
static void remmina_unlock_timer_reset(gpointer user_data)
GtkBuilder * remmina_public_gtk_builder_new_from_resource(gchar *resource)
static void remmina_unlock_timer_init()
void remmina_unlock_timer_destroy()
RemminaPref remmina_pref
Definition: rcw.c:79
gboolean unlocked
gint remmina_unlock_new(GtkWindow *parent)