Initial version, --vnc option only working.
[virt-click.git] / vnc-auth.c
1 /* virt-click
2  * Copyright (C) 2011 Red Hat Inc.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  *
18  * Parts are derived from 'gvnccapture':
19  *
20  * Vnc Image Capture
21  *
22  * Copyright (C) 2010 Daniel P. Berrange <dan@berrange.com>
23  *
24  * This library is free software; you can redistribute it and/or
25  * modify it under the terms of the GNU Lesser General Public
26  * License as published by the Free Software Foundation; either
27  * version 2.0 of the License, or (at your option) any later version.
28  *
29  * This library is distributed in the hope that it will be useful,
30  * but WITHOUT ANY WARRANTY; without even the implied warranty of
31  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
32  * Lesser General Public License for more details.
33  *
34  * You should have received a copy of the GNU Lesser General Public
35  * License along with this library; if not, write to the Free Software
36  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
37  */
38
39 #include <config.h>
40
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <unistd.h>
45
46 #ifdef HAVE_TERMIOS_H
47 #include <termios.h>
48 #endif
49
50 #include <glib/gi18n.h>
51 #include <vncconnection.h>
52 #include <vncbaseframebuffer.h>
53
54 #include "click.h"
55
56 static const guint preferable_auths[] = {
57   /*
58    * Both these two provide TLS based auth, and can layer
59    * all the other auth types on top. So these two must
60    * be the first listed
61    */
62   VNC_CONNECTION_AUTH_VENCRYPT,
63   VNC_CONNECTION_AUTH_TLS,
64
65   /*
66    * Then stackable auth types in order of preference
67    */
68   VNC_CONNECTION_AUTH_SASL,
69   VNC_CONNECTION_AUTH_MSLOGON,
70   VNC_CONNECTION_AUTH_VNC,
71
72   /*
73    * Or nothing at all
74    */
75   VNC_CONNECTION_AUTH_NONE
76 };
77
78
79 static gchar *
80 get_credential (const gchar *prompt, gboolean doecho)
81 {
82 #ifdef HAVE_TERMIOS_H
83   struct termios old, new;
84 #endif
85   gchar buf[100];
86   gchar *res;
87   int n = sizeof(buf);
88   ssize_t len;
89
90   printf("%s", prompt);
91   fflush(stdout);
92
93 #ifdef HAVE_TERMIOS_H
94   /* Turn echoing off and fail if we can't. */
95   if (!doecho && tcgetattr (fileno (stdin), &old) != 0)
96     return NULL;
97   new = old;
98   new.c_lflag &= ~ECHO;
99   if (!doecho && tcsetattr(fileno(stdin), TCSAFLUSH, &new) != 0)
100     return NULL;
101 #else
102   doecho = TRUE; /* Avoid unused parameter compile warning */
103 #endif
104
105   /* Read the password. */
106   if ((res = fgets(buf, n, stdin)) != NULL) {
107     len = strlen(res);
108     if (res[len-1] == '\n')
109       res[len-1] = '\0';
110   }
111
112 #ifdef HAVE_TERMIOS_H
113   /* Restore terminal. */
114   if (!doecho) {
115     printf("\n");
116     (void) tcsetattr(fileno (stdin), TCSAFLUSH, &old);
117   }
118 #endif
119
120   return res ? g_strdup(res) : NULL;
121 }
122
123 void
124 vc_vnc_auth_credential (VncConnection *conn, GValueArray *credList,
125                         gpointer opaque)
126 {
127   self_t *self = opaque;
128   guint i;
129   char **data;
130
131   data = g_new0(char *, credList->n_values);
132
133   for (i = 0 ; i < credList->n_values ; i++) {
134     GValue *cred = g_value_array_get_nth(credList, i);
135     switch (g_value_get_enum(cred)) {
136     case VNC_CONNECTION_CREDENTIAL_PASSWORD:
137       data[i] = get_credential ("Password: ", FALSE);
138       if (!data[i]) {
139         if (verbose)
140           fprintf (stderr, "vnc: failed to read password\n");
141         vnc_connection_shutdown(conn);
142         goto cleanup;
143       }
144       break;
145     case VNC_CONNECTION_CREDENTIAL_USERNAME:
146       data[i] = get_credential ("Username: ", TRUE);
147       if (!data[i]) {
148         if (verbose)
149           fprintf (stderr, "vnc: failed to read username\n");
150         vnc_connection_shutdown(conn);
151         goto cleanup;
152       }
153       break;
154     case VNC_CONNECTION_CREDENTIAL_CLIENTNAME:
155       data[i] = g_strdup ("virt-click");
156       break;
157     default:
158       break;
159     }
160   }
161   for (i = 0 ; i < credList->n_values ; i++) {
162     GValue *cred = g_value_array_get_nth(credList, i);
163     if (data[i]) {
164       if (!vnc_connection_set_credential(conn,
165                                          g_value_get_enum(cred),
166                                          data[i])) {
167         fprintf (stderr, "vnc: failed to set credential type %d %s\n",
168                  g_value_get_enum(cred), data[i]);
169         vnc_connection_shutdown(conn);
170       }
171     } else {
172       if (verbose)
173         fprintf (stderr, "vnc: unsupported credential type %d\n",
174                  g_value_get_enum(cred));
175       vnc_connection_shutdown(conn);
176     }
177   }
178
179  cleanup:
180   for (i = 0 ; i < credList->n_values ; i++)
181     g_free(data[i]);
182   g_free(data);
183 }
184
185 void
186 vc_vnc_auth_choose_type (VncConnection *conn,
187                          GValueArray *types,
188                          gpointer opaque G_GNUC_UNUSED)
189 {
190   guint i, j;
191
192   if (!types->n_values) {
193     VNC_DEBUG("No auth types to choose from");
194     return;
195   }
196
197   for (i = 0 ; i < G_N_ELEMENTS(preferable_auths) ; i++) {
198     int pref = preferable_auths[i];
199
200     for (j = 0 ; j < types->n_values ; j++) {
201       GValue *type = g_value_array_get_nth(types, j);
202       VNC_DEBUG("Compare %d vs %d", pref, g_value_get_enum(type));
203       if (pref == g_value_get_enum(type)) {
204         VNC_DEBUG("Chosen auth %d", pref);
205         vnc_connection_set_auth_type(conn, pref);
206         return;
207       }
208     }
209   }
210
211   GValue *type = g_value_array_get_nth(types, 0);
212   VNC_DEBUG("Chosen default auth %d", g_value_get_enum(type));
213   vnc_connection_set_auth_type(conn, g_value_get_enum(type));
214 }