diff options
-rwxr-xr-x | data/desktop/remmina-file-wrapper.in | 6 | ||||
-rw-r--r-- | src/remmina.1 | 24 | ||||
-rw-r--r-- | src/remmina.c | 11 | ||||
-rw-r--r-- | src/remmina_exec.c | 207 | ||||
-rw-r--r-- | src/remmina_exec.h | 3 |
5 files changed, 235 insertions, 16 deletions
diff --git a/data/desktop/remmina-file-wrapper.in b/data/desktop/remmina-file-wrapper.in index a2ec5933e..ccf6dbe56 100755 --- a/data/desktop/remmina-file-wrapper.in +++ b/data/desktop/remmina-file-wrapper.in @@ -34,13 +34,13 @@ export GLADE_HOME="$USRBIN/../share/remmina/ui/" case "$@" in *rdp:*) - "$REMMINA" "${@#rdp:\/\/}" + "$REMMINA" "${@}" ;; *spice:*) - "$REMMINA" "${@#spice:\/\/}" + "$REMMINA" "${@}" ;; *vnc:*) - "$REMMINA" "${@#vnc:\/\/}" + "$REMMINA" "${@}" ;; *remmina:*) "$REMMINA" "${@#remmina:\/\/}" diff --git a/src/remmina.1 b/src/remmina.1 index a9faec2d7..721333074 100644 --- a/src/remmina.1 +++ b/src/remmina.1 @@ -47,7 +47,7 @@ Show help options .It Fl a Show about dialog .It Fl c, -connect\fR=\fIFILE\fR -Directly connect to desktop using options described by file, file type can be either .remmina or one supported by a file import capable plugin +Connect directly either to a desktop using options described in a file, or a supported URI (RDP, VNC or SPICE). The filetype can be ".remmina" or one supported by a plugin capable of importing files .It Fl e, -edit\fR=\fIFILE\fR Open and edit desktop connection using options described by file, file type can be either .remmina or one supported by a file import capable plugin .It Fl k, -kiosk\fR @@ -72,6 +72,8 @@ Show the application's version Modify connection profile, require also \-\-set\-option .It --set-option \fIOPTION[=VALUE]\fR Set one or more profile settings, to be used with \-\-update\-profile +.It --encrypt-password\fR +Encrypt a password .It --display\fR=\fIDISPLAY\fR X display to use .El @@ -84,6 +86,26 @@ To connect using an exisitng connection profile use: .fi .RE .Lp +To quick connect using a URI: +.RS +.nf +remmina -c rdp://username:password@server +remmina -c rdp://domain\\\\username@server +remmina -c vnc://username@server +remmina -c vnc://server?VncUsername=username +remmina -c spice://server + +To quick connect using a URI along with an encrypted password: +remmina -c rdp://username:encrypted-password@server +remmina -c vnc://username:encrypted-password@server +remmina -c vnc://server?VncUsername=username\\&VncPassword=encrypted-password + +To encrypt a password for use with a URI: +remmina --encrypt-password + +.fi +.RE +.Lp To update username and password and set a different resolution mode of a remmina connection profile use: .RS .nf diff --git a/src/remmina.c b/src/remmina.c index dbeae30a9..0d0dc7d96 100644 --- a/src/remmina.c +++ b/src/remmina.c @@ -83,9 +83,9 @@ static GOptionEntry remmina_options[] = // TRANSLATORS: Shown in terminal. Do not use characters that may be not supported on a terminal { "about", 'a', 0, G_OPTION_ARG_NONE, NULL, N_("Show \'About\'"), NULL }, // TRANSLATORS: Shown in terminal. Do not use characters that may be not supported on a terminal - { "connect", 'c', 0, G_OPTION_ARG_FILENAME_ARRAY, NULL, N_("Connect to desktop described in file (.remmina or type supported by plugin)"), N_("FILE") }, + { "connect", 'c', 0, G_OPTION_ARG_FILENAME_ARRAY, NULL, N_("Connect either to a desktop described in a file (.remmina or a filetype supported by a plugin) or a supported URI (RDP, VNC or SPICE)"), N_("FILE") }, // TRANSLATORS: Shown in terminal. Do not use characters that may be not supported on a terminal - { G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_FILENAME_ARRAY, NULL, N_("Connect to desktop described in file (.remmina or type supported by plugin)"), N_("FILE") }, + { G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_FILENAME_ARRAY, NULL, N_("Connect to a desktop described in a file (.remmina or a type supported by a plugin)"), N_("FILE") }, // TRANSLATORS: Shown in terminal. Do not use characters that may be not supported on a terminal { "edit", 'e', 0, G_OPTION_ARG_FILENAME_ARRAY, NULL, N_("Edit desktop connection described in file (.remmina or type supported by plugin)"), N_("FILE") }, { "help", '?', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, NULL, NULL, NULL }, @@ -116,6 +116,7 @@ static GOptionEntry remmina_options[] = { "update-profile", 0, 0, G_OPTION_ARG_FILENAME, NULL, N_("Modify connection profile (requires --set-option)"), NULL }, // TRANSLATORS: Shown in terminal. Do not use characters that may be not supported on a terminal { "set-option", 0, 0, G_OPTION_ARG_STRING_ARRAY, NULL, N_("Set one or more profile settings, to be used with --update-profile"), NULL }, + { "encrypt-password", 0, 0, G_OPTION_ARG_NONE, NULL, N_("Encrypt a password"), NULL }, { NULL } }; @@ -226,6 +227,12 @@ static gint remmina_on_command_line(GApplication *app, GApplicationCommandLine * executed = TRUE; } + if (g_variant_dict_lookup_value(opts, "encrypt-password", NULL)) { + remmina_exec_command(REMMINA_COMMAND_ENCRYPT_PASSWORD, NULL); + executed = TRUE; + status = 1; + } + if (!executed) remmina_exec_command(REMMINA_COMMAND_MAIN, NULL); diff --git a/src/remmina_exec.c b/src/remmina_exec.c index 17d76131f..bcdccb081 100644 --- a/src/remmina_exec.c +++ b/src/remmina_exec.c @@ -56,6 +56,7 @@ #include "remmina_icon.h" #include "remmina/remmina_trace_calls.h" #include "remmina_file_manager.h" +#include "remmina_crypt.h" #ifdef SNAP_BUILD # define ISSNAP "- SNAP Build -" @@ -214,16 +215,34 @@ static void remmina_exec_autostart_cb(RemminaFile *remminafile, gpointer user_da } } + void remmina_exec_command(RemminaCommandType command, const gchar* data) { TRACE_CALL(__func__); - gchar* s1; - gchar* s2; - GtkWidget* widget; - GtkWindow* mainwindow; - GtkDialog* prefdialog; - RemminaEntryPlugin* plugin; - + gchar *s1; + gchar *s2; + gchar *p; + gchar **protocolserver; + gchar **userat; + gchar **userpass; + gchar **domainuser; + gchar **serverquery; + gchar **querystring; + gchar **querystringpart; + gchar **querystringpartkv; + gchar *protocol; + gchar *server; + gchar *user; + gchar *password; + gchar *value; + gchar *temp; + RemminaFile *remminafile; + GtkWidget *widget; + GtkWindow *mainwindow; + GtkDialog *prefdialog; + RemminaEntryPlugin *plugin; + int i; + int ch; mainwindow = remmina_main_get_window(); switch (command) { @@ -274,7 +293,154 @@ void remmina_exec_command(RemminaCommandType command, const gchar* data) * we can implement multi profile connection: * https://gitlab.com/Remmina/Remmina/issues/915 */ - rcw_open_from_filename(data); + protocol = NULL; + if (strncmp("rdp://", data, 6) == 0 || strncmp("RDP://", data, 6) == 0) + protocol = "RDP"; + else if (strncmp("vnc://", data, 6) == 0 || strncmp("VNC://", data, 6) == 0) + protocol = "VNC"; + else if (strncmp("spice://", data, 8) == 0 || strncmp("SPICE://", data, 8) == 0) + protocol = "SPICE"; + + if (protocol != NULL) { + protocolserver = g_strsplit(data, "://", 2); + server = g_strdup(protocolserver[1]); + + // Support loading .remmina files using handler + if ((p = strrchr(server, '.')) != NULL && g_strcmp0(p + 1, "remmina") == 0) { + g_strfreev(protocolserver); + temp = g_uri_unescape_string(server, NULL); + g_free(server); + server = temp; + rcw_open_from_filename(server); + break; + } + + remminafile = remmina_file_new(); + + if (strcmp(protocol, "RDP") == 0) { + // https://tools.ietf.org/html/rfc3986 + // "rdp://" [ userinfo "@" ] host [ ":" port ] + + // Check for username@server + if (strstr(server, "@") != NULL) { + userat = g_strsplit(server, "@", 2); + + // Check for username:password + if (strstr(userat[0], ":") != NULL) { + userpass = g_strsplit(userat[0], ":", 2); + user = g_uri_unescape_string(userpass[0], NULL); + password = g_uri_unescape_string(userpass[1], NULL); + + // Try to decrypt the password field if it contains = + temp = password != NULL && strrchr(password, '=') != NULL ? remmina_crypt_decrypt(password) : NULL; + if (temp != NULL) { + g_free(password); + password = temp; + } + remmina_file_set_string(remminafile, "password", password); + g_free(password); + g_strfreev(userpass); + } else { + user = g_uri_unescape_string(userat[0], NULL); + } + + // Check for domain\user + if (strstr(user, "\\") != NULL) { + domainuser = g_strsplit(user, "\\", 2); + remmina_file_set_string(remminafile, "domain", domainuser[0]); + g_free(user); + user = g_strdup(domainuser[1]); + } + + remmina_file_set_string(remminafile, "username", user); + g_free(user); + g_free(server); + server = g_strdup(userat[1]); + g_strfreev(userat); + } + } else if (strcmp(protocol, "VNC") == 0) { + // https://tools.ietf.org/html/rfc7869 + // VncUsername, VncPassword and ColorLevel supported for vnc-params + // "vnc://" [ userinfo "@" ] [ host [ ":" port ] ] [ "?" [ vnc-params ] ] + + // Check for username@server + if (strstr(server, "@") != NULL) { + userat = g_strsplit(server, "@", 2); + + // Check for username:password + if (strstr(userat[0], ":") != NULL) { + userpass = g_strsplit(userat[0], ":", 2); + user = g_uri_unescape_string(userpass[0], NULL); + remmina_file_set_string(remminafile, "username", user); + g_free(user); + password = g_uri_unescape_string(userpass[1], NULL); + + // Try to decrypt password field if it contains = + temp = password != NULL && strrchr(password, '=') != NULL ? remmina_crypt_decrypt(password) : NULL; + if (temp != NULL) { + g_free(password); + password = temp; + } + remmina_file_set_string(remminafile, "password", password); + g_free(password); + g_strfreev(userpass); + } else { + user = g_uri_unescape_string(userat[0], NULL); + remmina_file_set_string(remminafile, "username", user); + g_free(user); + } + g_free(server); + server = g_strdup(userat[1]); + g_strfreev(userat); + } + + // Check for query string parameters + if (strstr(server, "?") != NULL) { + serverquery = g_strsplit(server, "?", 2); + querystring = g_strsplit(serverquery[1], "&", -1); + for (querystringpart = querystring; *querystringpart; querystringpart++) { + if (strstr(*querystringpart, "=") != NULL) { + querystringpartkv = g_strsplit(*querystringpart, "=", 2); + value = g_uri_unescape_string(querystringpartkv[1], NULL); + if (strcmp(querystringpartkv[0], "VncPassword") == 0) { + // Try to decrypt password field if it contains = + temp = value != NULL && strrchr(value, '=') != NULL ? remmina_crypt_decrypt(value) : NULL; + if (temp != NULL) { + g_free(value); + value = temp; + } + remmina_file_set_string(remminafile, "password", value); + } else if (strcmp(querystringpartkv[0], "VncUsername") == 0) { + remmina_file_set_string(remminafile, "username", value); + } else if (strcmp(querystringpartkv[0], "ColorLevel") == 0) { + remmina_file_set_string(remminafile, "colordepth", value); + } + g_free(value); + g_strfreev(querystringpartkv); + } + } + g_strfreev(querystring); + g_free(server); + server = g_strdup(serverquery[0]); + g_strfreev(serverquery); + } + } + + // Unescape server + temp = g_uri_unescape_string(server, NULL); + g_free(server); + server = temp; + + remmina_file_set_string(remminafile, "server", server); + remmina_file_set_string(remminafile, "name", server); + remmina_file_set_string(remminafile, "sound", "off"); + remmina_file_set_string(remminafile, "protocol", protocol); + g_free(server); + g_strfreev(protocolserver); + rcw_open_from_file(remminafile); + } else { + rcw_open_from_filename(data); + } break; case REMMINA_COMMAND_EDIT: @@ -328,6 +494,30 @@ void remmina_exec_command(RemminaCommandType command, const gchar* data) } break; + case REMMINA_COMMAND_ENCRYPT_PASSWORD: + i = 0; + g_print("Enter the password you want to encrypt: "); + temp = (char *)g_malloc(255 * sizeof(char)); + while ((ch = getchar()) != EOF && ch != '\n') { + if (i < 254) { + temp[i] = ch; + i++; + } + } + temp[i] = '\0'; + s1 = remmina_crypt_encrypt(temp); + s2 = g_uri_escape_string(s1, NULL, TRUE); + g_print("\nEncrypted password: %s\n\n", s1); + g_print("Usage:\n"); + g_print("rdp://username:%s@server\n", s1); + g_print("vnc://username:%s@server\n", s1); + g_print("vnc://server?VncUsername=user\\&VncPassword=%s\n", s2); + g_free(s1); + g_free(s2); + g_free(temp); + remmina_exec_exitremmina(); + break; + case REMMINA_COMMAND_EXIT: remmina_widget_pool_foreach(disable_rcw_delete_confirm_cb, NULL); remmina_exec_exitremmina(); @@ -337,4 +527,3 @@ void remmina_exec_command(RemminaCommandType command, const gchar* data) break; } } - diff --git a/src/remmina_exec.h b/src/remmina_exec.h index adbb6ced2..5cb1afc2b 100644 --- a/src/remmina_exec.h +++ b/src/remmina_exec.h @@ -49,7 +49,8 @@ typedef enum { REMMINA_COMMAND_FULL_VERSION = 8, REMMINA_COMMAND_PLUGIN = 9, REMMINA_COMMAND_EXIT = 10, - REMMINA_COMMAND_AUTOSTART = 11 + REMMINA_COMMAND_AUTOSTART = 11, + REMMINA_COMMAND_ENCRYPT_PASSWORD = 12 } RemminaCommandType; typedef enum { |