e47c9328cf3ea082241b2a9d93a387d21aa3ef6b
[platform/adaptation/emulator/spice-vdagent.git] / src / vdagentd.c
1 /*  vdagentd.c vdagentd (daemon) code
2
3     Copyright 2010-2013 Red Hat, Inc.
4     Copyright (c) 2014 Samsung Electronics Co., Ltd.
5
6     Red Hat Authors:
7     Hans de Goede <hdegoede@redhat.com>
8     Gerd Hoffmann <kraxel@redhat.com>
9
10     This program is free software: you can redistribute it and/or modify
11     it under the terms of the GNU General Public License as published by
12     the Free Software Foundation, either version 3 of the License, or   
13     (at your option) any later version.
14
15     This program is distributed in the hope that it will be useful,
16     but WITHOUT ANY WARRANTY; without even the implied warranty of 
17     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  
18     GNU General Public License for more details.
19
20     You should have received a copy of the GNU General Public License
21     along with this program.  If not, see <http://www.gnu.org/licenses/>.
22
23     * Modifications by Samsung Electronics Co., Ltd.
24     1. modified pidfilename path
25 */
26 #ifdef HAVE_CONFIG_H
27 #include <config.h>
28 #endif
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include <fcntl.h>
35 #include <errno.h>
36 #include <signal.h>
37 #include <syslog.h>
38 #include <sys/select.h>
39 #include <sys/stat.h>
40 #include <spice/vd_agent.h>
41 #include <glib.h>
42
43 #include "udscs.h"
44 #include "vdagentd-proto.h"
45 #include "vdagentd-proto-strings.h"
46 #include "vdagentd-uinput.h"
47 #include "vdagentd-xorg-conf.h"
48 #include "vdagent-virtio-port.h"
49 #include "session-info.h"
50
51 struct agent_data {
52     char *session;
53     int width;
54     int height;
55     struct vdagentd_guest_xorg_resolution *screen_info;
56     int screen_count;
57 };
58
59 /* variables */
60 static const char *pidfilename = "/opt/var/run/spice-vdagentd/spice-vdagentd.pid";
61 static const char *portdev = "/dev/virtio-ports/com.redhat.spice.0";
62 static const char *vdagentd_socket = VDAGENTD_SOCKET;
63 static const char *uinput_device = "/dev/uinput";
64 static int debug = 0;
65 static int uinput_fake = 0;
66 static struct udscs_server *server = NULL;
67 static struct vdagent_virtio_port *virtio_port = NULL;
68 static GHashTable *active_xfers = NULL;
69 static struct session_info *session_info = NULL;
70 static struct vdagentd_uinput *uinput = NULL;
71 static VDAgentMonitorsConfig *mon_config = NULL;
72 static uint32_t *capabilities = NULL;
73 static int capabilities_size = 0;
74 static const char *active_session = NULL;
75 static unsigned int session_count = 0;
76 static struct udscs_connection *active_session_conn = NULL;
77 static int agent_owns_clipboard[256] = { 0, };
78 static int quit = 0;
79 static int retval = 0;
80 static int client_connected = 0;
81
82 /* utility functions */
83 /* vdagentd <-> spice-client communication handling */
84 static void send_capabilities(struct vdagent_virtio_port *vport,
85     uint32_t request)
86 {
87     VDAgentAnnounceCapabilities *caps;
88     uint32_t size;
89
90     size = sizeof(*caps) + VD_AGENT_CAPS_BYTES;
91     caps = calloc(1, size);
92     if (!caps) {
93         syslog(LOG_ERR, "out of memory allocating capabilities array (write)");
94         return;
95     }
96
97     caps->request = request;
98     VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_MOUSE_STATE);
99     VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_MONITORS_CONFIG);
100     VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_REPLY);
101     VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_CLIPBOARD_BY_DEMAND);
102     VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_CLIPBOARD_SELECTION);
103     VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_SPARSE_MONITORS_CONFIG);
104     VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_GUEST_LINEEND_LF);
105
106     vdagent_virtio_port_write(vport, VDP_CLIENT_PORT,
107                               VD_AGENT_ANNOUNCE_CAPABILITIES, 0,
108                               (uint8_t *)caps, size);
109     free(caps);
110 }
111
112 static void do_client_disconnect(void)
113 {
114     if (client_connected) {
115         udscs_server_write_all(server, VDAGENTD_CLIENT_DISCONNECTED, 0, 0,
116                                NULL, 0);
117         client_connected = 0;
118     }
119 }
120
121 static void do_client_monitors(struct vdagent_virtio_port *vport, int port_nr,
122     VDAgentMessage *message_header, VDAgentMonitorsConfig *new_monitors)
123 {
124     VDAgentReply reply;
125     uint32_t size;
126
127     /* Store monitor config to send to agents when they connect */
128     size = sizeof(VDAgentMonitorsConfig) +
129            new_monitors->num_of_monitors * sizeof(VDAgentMonConfig);
130     if (message_header->size != size) {
131         syslog(LOG_ERR, "invalid message size for VDAgentMonitorsConfig");
132         return;
133     }
134
135     vdagentd_write_xorg_conf(new_monitors);
136
137     if (!mon_config ||
138             mon_config->num_of_monitors != new_monitors->num_of_monitors) {
139         free(mon_config);
140         mon_config = malloc(size);
141         if (!mon_config) {
142             syslog(LOG_ERR, "out of memory allocating monitors config");
143             return;
144         }
145     }
146     memcpy(mon_config, new_monitors, size);
147
148     /* Send monitor config to currently active agent */
149     if (active_session_conn)
150         udscs_write(active_session_conn, VDAGENTD_MONITORS_CONFIG, 0, 0,
151                     (uint8_t *)mon_config, size);
152
153     /* Acknowledge reception of monitors config to spice server / client */
154     reply.type  = VD_AGENT_MONITORS_CONFIG;
155     reply.error = VD_AGENT_SUCCESS;
156     vdagent_virtio_port_write(vport, port_nr, VD_AGENT_REPLY, 0,
157                               (uint8_t *)&reply, sizeof(reply));
158 }
159
160 static void do_client_capabilities(struct vdagent_virtio_port *vport,
161     VDAgentMessage *message_header,
162     VDAgentAnnounceCapabilities *caps)
163 {
164     int new_size = VD_AGENT_CAPS_SIZE_FROM_MSG_SIZE(message_header->size);
165
166     if (capabilities_size != new_size) {
167         capabilities_size = new_size;
168         free(capabilities);
169         capabilities = malloc(capabilities_size * sizeof(uint32_t));
170         if (!capabilities) {
171             syslog(LOG_ERR, "oom allocating capabilities array (read)");
172             capabilities_size = 0;
173             return;
174         }
175     }
176     memcpy(capabilities, caps->caps, capabilities_size * sizeof(uint32_t));
177     if (caps->request) {
178         /* Report the previous client has disconneced. */
179         do_client_disconnect();
180         if (debug)
181             syslog(LOG_DEBUG, "New client connected");
182         client_connected = 1;
183         send_capabilities(vport, 0);
184     }
185 }
186
187 static void do_client_clipboard(struct vdagent_virtio_port *vport,
188     VDAgentMessage *message_header, uint8_t *data)
189 {
190     uint32_t msg_type = 0, data_type = 0, size = message_header->size;
191     uint8_t selection = VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD;
192
193     if (!active_session_conn) {
194         syslog(LOG_WARNING,
195                "Could not find an agent connection belonging to the "
196                "active session, ignoring client clipboard request");
197         return;
198     }
199
200     if (VD_AGENT_HAS_CAPABILITY(capabilities, capabilities_size,
201                                 VD_AGENT_CAP_CLIPBOARD_SELECTION)) {
202       selection = data[0];
203       data += 4;
204       size -= 4;
205     }
206
207     switch (message_header->type) {
208     case VD_AGENT_CLIPBOARD_GRAB:
209         msg_type = VDAGENTD_CLIPBOARD_GRAB;
210         agent_owns_clipboard[selection] = 0;
211         break;
212     case VD_AGENT_CLIPBOARD_REQUEST: {
213         VDAgentClipboardRequest *req = (VDAgentClipboardRequest *)data;
214         msg_type = VDAGENTD_CLIPBOARD_REQUEST;
215         data_type = req->type;
216         data = NULL;
217         size = 0;
218         break;
219     }
220     case VD_AGENT_CLIPBOARD: {
221         VDAgentClipboard *clipboard = (VDAgentClipboard *)data;
222         msg_type = VDAGENTD_CLIPBOARD_DATA;
223         data_type = clipboard->type;
224         size = size - sizeof(VDAgentClipboard);
225         data = clipboard->data;
226         break;
227     }
228     case VD_AGENT_CLIPBOARD_RELEASE:
229         msg_type = VDAGENTD_CLIPBOARD_RELEASE;
230         data = NULL;
231         size = 0;
232         break;
233     }
234
235     udscs_write(active_session_conn, msg_type, selection, data_type,
236                 data, size);
237 }
238
239 static void cancel_file_xfer(struct vdagent_virtio_port *vport,
240                              const char *msg, uint32_t id)
241 {
242     VDAgentFileXferStatusMessage status = {
243         .id = id,
244         .result = VD_AGENT_FILE_XFER_STATUS_CANCELLED,
245     };
246     syslog(LOG_WARNING, msg, id);
247     if (vport)
248         vdagent_virtio_port_write(vport, VDP_CLIENT_PORT,
249                                   VD_AGENT_FILE_XFER_STATUS, 0,
250                                   (uint8_t *)&status, sizeof(status));
251 }
252
253 static void do_client_file_xfer(struct vdagent_virtio_port *vport,
254                                 VDAgentMessage *message_header,
255                                 uint8_t *data)
256 {
257     uint32_t msg_type, id;
258     struct udscs_connection *conn;
259
260     switch (message_header->type) {
261     case VD_AGENT_FILE_XFER_START: {
262         VDAgentFileXferStartMessage *s = (VDAgentFileXferStartMessage *)data;
263         if (!active_session_conn) {
264             cancel_file_xfer(vport,
265                "Could not find an agent connnection belonging to the "
266                "active session, cancelling client file-xfer request %u",
267                s->id);
268             return;
269         }
270         udscs_write(active_session_conn, VDAGENTD_FILE_XFER_START, 0, 0,
271                     data, message_header->size);
272         return;
273     }
274     case VD_AGENT_FILE_XFER_STATUS: {
275         VDAgentFileXferStatusMessage *s = (VDAgentFileXferStatusMessage *)data;
276         msg_type = VDAGENTD_FILE_XFER_STATUS;
277         id = s->id;
278         break;
279     }
280     case VD_AGENT_FILE_XFER_DATA: {
281         VDAgentFileXferDataMessage *d = (VDAgentFileXferDataMessage *)data;
282         msg_type = VDAGENTD_FILE_XFER_DATA;
283         id = d->id;
284         break;
285     }
286     }
287
288     conn = g_hash_table_lookup(active_xfers, GUINT_TO_POINTER(id));
289     if (!conn) {
290         if (debug)
291             syslog(LOG_DEBUG, "Could not find file-xfer %u (cancelled?)", id);
292         return;
293     }
294     udscs_write(conn, msg_type, 0, 0, data, message_header->size);
295 }
296
297 int virtio_port_read_complete(
298         struct vdagent_virtio_port *vport,
299         int port_nr,
300         VDAgentMessage *message_header,
301         uint8_t *data)
302 {
303     uint32_t min_size = 0;
304
305     if (message_header->protocol != VD_AGENT_PROTOCOL) {
306         syslog(LOG_ERR, "message with wrong protocol version ignoring");
307         return 0;
308     }
309
310     switch (message_header->type) {
311     case VD_AGENT_MOUSE_STATE:
312         if (message_header->size != sizeof(VDAgentMouseState))
313             goto size_error;
314         vdagentd_uinput_do_mouse(&uinput, (VDAgentMouseState *)data);
315         if (!uinput) {
316             /* Try to re-open the tablet */
317             struct agent_data *agent_data =
318                 udscs_get_user_data(active_session_conn);
319             if (agent_data)
320                 uinput = vdagentd_uinput_create(uinput_device,
321                                                 agent_data->width,
322                                                 agent_data->height,
323                                                 agent_data->screen_info,
324                                                 agent_data->screen_count,
325                                                 debug > 1,
326                                                 uinput_fake);
327             if (!uinput) {
328                 syslog(LOG_CRIT, "Fatal uinput error");
329                 retval = 1;
330                 quit = 1;
331             }
332         }
333         break;
334     case VD_AGENT_MONITORS_CONFIG:
335         if (message_header->size < sizeof(VDAgentMonitorsConfig))
336             goto size_error;
337         do_client_monitors(vport, port_nr, message_header,
338                     (VDAgentMonitorsConfig *)data);
339         break;
340     case VD_AGENT_ANNOUNCE_CAPABILITIES:
341         if (message_header->size < sizeof(VDAgentAnnounceCapabilities))
342             goto size_error;
343         do_client_capabilities(vport, message_header,
344                         (VDAgentAnnounceCapabilities *)data);
345         break;
346     case VD_AGENT_CLIPBOARD_GRAB:
347     case VD_AGENT_CLIPBOARD_REQUEST:
348     case VD_AGENT_CLIPBOARD:
349     case VD_AGENT_CLIPBOARD_RELEASE:
350         switch (message_header->type) {
351         case VD_AGENT_CLIPBOARD_GRAB:
352             min_size = sizeof(VDAgentClipboardGrab); break;
353         case VD_AGENT_CLIPBOARD_REQUEST:
354             min_size = sizeof(VDAgentClipboardRequest); break;
355         case VD_AGENT_CLIPBOARD:
356             min_size = sizeof(VDAgentClipboard); break;
357         }
358         if (VD_AGENT_HAS_CAPABILITY(capabilities, capabilities_size,
359                                     VD_AGENT_CAP_CLIPBOARD_SELECTION)) {
360             min_size += 4;
361         }
362         if (message_header->size < min_size) {
363             goto size_error;
364         }
365         do_client_clipboard(vport, message_header, data);
366         break;
367     case VD_AGENT_FILE_XFER_START:
368     case VD_AGENT_FILE_XFER_STATUS:
369     case VD_AGENT_FILE_XFER_DATA:
370         do_client_file_xfer(vport, message_header, data);
371         break;
372     case VD_AGENT_CLIENT_DISCONNECTED:
373         vdagent_virtio_port_reset(vport, VDP_CLIENT_PORT);
374         do_client_disconnect();
375         break;
376     default:
377         syslog(LOG_WARNING, "unknown message type %d, ignoring",
378                message_header->type);
379     }
380
381     return 0;
382
383 size_error:
384     syslog(LOG_ERR, "read: invalid message size: %u for message type: %u",
385            message_header->size, message_header->type);
386     return 0;
387 }
388
389 /* vdagentd <-> vdagent communication handling */
390 int do_agent_clipboard(struct udscs_connection *conn,
391         struct udscs_message_header *header, const uint8_t *data)
392 {
393     uint8_t selection = header->arg1;
394     uint32_t msg_type = 0, data_type = -1, size = header->size;
395
396     if (!VD_AGENT_HAS_CAPABILITY(capabilities, capabilities_size,
397                                  VD_AGENT_CAP_CLIPBOARD_BY_DEMAND))
398         goto error;
399
400     /* Check that this agent is from the currently active session */
401     if (conn != active_session_conn) {
402         if (debug)
403             syslog(LOG_DEBUG, "%p clipboard req from agent which is not in "
404                               "the active session?", conn);
405         goto error;
406     }
407
408     if (!virtio_port) {
409         syslog(LOG_ERR, "Clipboard req from agent but no client connection");
410         goto error;
411     }
412
413     if (!VD_AGENT_HAS_CAPABILITY(capabilities, capabilities_size,
414                                  VD_AGENT_CAP_CLIPBOARD_SELECTION) &&
415             selection != VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD) {
416         goto error;
417     }
418
419     switch (header->type) {
420     case VDAGENTD_CLIPBOARD_GRAB:
421         msg_type = VD_AGENT_CLIPBOARD_GRAB;
422         agent_owns_clipboard[selection] = 1;
423         break;
424     case VDAGENTD_CLIPBOARD_REQUEST:
425         msg_type = VD_AGENT_CLIPBOARD_REQUEST;
426         data_type = header->arg2;
427         size = 0;
428         break;
429     case VDAGENTD_CLIPBOARD_DATA:
430         msg_type = VD_AGENT_CLIPBOARD;
431         data_type = header->arg2;
432         break;
433     case VDAGENTD_CLIPBOARD_RELEASE:
434         msg_type = VD_AGENT_CLIPBOARD_RELEASE;
435         size = 0;
436         agent_owns_clipboard[selection] = 0;
437         break;
438     }
439
440     if (size != header->size) {
441         syslog(LOG_ERR,
442                "unexpected extra data in clipboard msg, disconnecting agent");
443         return -1;
444     }
445
446     if (VD_AGENT_HAS_CAPABILITY(capabilities, capabilities_size,
447                                 VD_AGENT_CAP_CLIPBOARD_SELECTION)) {
448         size += 4;
449     }
450     if (data_type != -1) {
451         size += 4;
452     }
453
454     vdagent_virtio_port_write_start(virtio_port, VDP_CLIENT_PORT, msg_type,
455                                     0, size);
456
457     if (VD_AGENT_HAS_CAPABILITY(capabilities, capabilities_size,
458                                 VD_AGENT_CAP_CLIPBOARD_SELECTION)) {
459         uint8_t sel[4] = { selection, 0, 0, 0 };
460         vdagent_virtio_port_write_append(virtio_port, sel, 4);
461     }
462     if (data_type != -1) {
463         vdagent_virtio_port_write_append(virtio_port, (uint8_t*)&data_type, 4);
464     }
465
466     vdagent_virtio_port_write_append(virtio_port, data, header->size);
467
468     return 0;
469
470 error:
471     if (header->type == VDAGENTD_CLIPBOARD_REQUEST) {
472         /* Let the agent know no answer is coming */
473         udscs_write(conn, VDAGENTD_CLIPBOARD_DATA,
474                     selection, VD_AGENT_CLIPBOARD_NONE, NULL, 0);
475     }
476     return 0;
477 }
478
479 /* When we open the vdagent virtio channel, the server automatically goes into
480    client mouse mode, so we can only have the channel open when we know the
481    active session resolution. This function checks that we have an agent in the
482    active session, and that it has told us its resolution. If these conditions
483    are met it sets the uinput tablet device's resolution and opens the virtio
484    channel (if it is not already open). If these conditions are not met, it
485    closes both. */
486 static void check_xorg_resolution(void)
487 {
488     struct agent_data *agent_data = udscs_get_user_data(active_session_conn);
489
490     if (agent_data && agent_data->screen_info) {
491         if (!uinput)
492             uinput = vdagentd_uinput_create(uinput_device,
493                                             agent_data->width,
494                                             agent_data->height,
495                                             agent_data->screen_info,
496                                             agent_data->screen_count,
497                                             debug > 1,
498                                             uinput_fake);
499         else
500             vdagentd_uinput_update_size(&uinput,
501                                         agent_data->width,
502                                         agent_data->height,
503                                         agent_data->screen_info,
504                                         agent_data->screen_count);
505         if (!uinput) {
506             syslog(LOG_CRIT, "Fatal uinput error");
507             retval = 1;
508             quit = 1;
509             return;
510         }
511
512         if (!virtio_port) {
513             syslog(LOG_INFO, "opening vdagent virtio channel");
514             virtio_port = vdagent_virtio_port_create(portdev,
515                                                      virtio_port_read_complete,
516                                                      NULL);
517             if (!virtio_port) {
518                 syslog(LOG_CRIT, "Fatal error opening vdagent virtio channel");
519                 retval = 1;
520                 quit = 1;
521                 return;
522             }
523             send_capabilities(virtio_port, 1);
524         }
525     } else {
526 #ifndef WITH_STATIC_UINPUT
527         vdagentd_uinput_destroy(&uinput);
528 #endif
529         if (virtio_port) {
530             vdagent_virtio_port_flush(&virtio_port);
531             vdagent_virtio_port_destroy(&virtio_port);
532             syslog(LOG_INFO, "closed vdagent virtio channel");
533         }
534     }
535 }
536
537 static int connection_matches_active_session(struct udscs_connection **connp,
538     void *priv)
539 {
540     struct udscs_connection **conn_ret = (struct udscs_connection **)priv;
541     struct agent_data *agent_data = udscs_get_user_data(*connp);
542
543     /* Check if this connection matches the currently active session */
544     if (!agent_data->session || !active_session)
545         return 0;
546     if (strcmp(agent_data->session, active_session))
547         return 0;
548
549     *conn_ret = *connp;
550     return 1;
551 }
552
553 void release_clipboards(void)
554 {
555     uint8_t sel;
556
557     for (sel = 0; sel < VD_AGENT_CLIPBOARD_SELECTION_SECONDARY; ++sel) {
558         if (agent_owns_clipboard[sel] && virtio_port) {
559             vdagent_virtio_port_write(virtio_port, VDP_CLIENT_PORT,
560                                       VD_AGENT_CLIPBOARD_RELEASE, 0, &sel, 1);
561         }
562         agent_owns_clipboard[sel] = 0;
563     }
564 }
565
566 void update_active_session_connection(struct udscs_connection *new_conn)
567 {
568     if (session_info) {
569         new_conn = NULL;
570         if (!active_session)
571             active_session = session_info_get_active_session(session_info);
572         session_count = udscs_server_for_all_clients(server,
573                                          connection_matches_active_session,
574                                          (void*)&new_conn);
575     } else {
576         if (new_conn)
577             session_count++;
578         else
579             session_count--;
580     }
581
582     if (new_conn && session_count != 1) {
583         syslog(LOG_ERR, "multiple agents in one session, "
584                "disabling agent to avoid potential information leak");
585         new_conn = NULL;
586     }
587
588     if (new_conn == active_session_conn)
589         return;
590
591     active_session_conn = new_conn;
592     if (debug)
593         syslog(LOG_DEBUG, "%p is now the active session", new_conn);
594     if (active_session_conn && mon_config)
595         udscs_write(active_session_conn, VDAGENTD_MONITORS_CONFIG, 0, 0,
596                     (uint8_t *)mon_config, sizeof(VDAgentMonitorsConfig) +
597                     mon_config->num_of_monitors * sizeof(VDAgentMonConfig));
598
599     release_clipboards();
600
601     check_xorg_resolution();    
602 }
603
604 gboolean remove_active_xfers(gpointer key, gpointer value, gpointer conn)
605 {
606     if (value == conn) {
607         cancel_file_xfer(virtio_port, "Agent disc; cancelling file-xfer %u",
608                          GPOINTER_TO_UINT(key));
609         return 1;
610     } else
611         return 0;
612 }
613
614 void agent_connect(struct udscs_connection *conn)
615 {
616     struct agent_data *agent_data;
617
618     agent_data = calloc(1, sizeof(*agent_data));
619     if (!agent_data) {
620         syslog(LOG_ERR, "Out of memory allocating agent data, disconnecting");
621         udscs_destroy_connection(&conn);
622         return;
623     }
624
625     if (session_info) {
626         uint32_t pid = udscs_get_peer_cred(conn).pid;
627         agent_data->session = session_info_session_for_pid(session_info, pid);
628     }
629
630     udscs_set_user_data(conn, (void *)agent_data);
631     udscs_write(conn, VDAGENTD_VERSION, 0, 0,
632                 (uint8_t *)VERSION, strlen(VERSION) + 1);
633     update_active_session_connection(conn);
634 }
635
636 void agent_disconnect(struct udscs_connection *conn)
637 {
638     struct agent_data *agent_data = udscs_get_user_data(conn);
639
640     g_hash_table_foreach_remove(active_xfers, remove_active_xfers, conn);
641
642     free(agent_data->session);
643     agent_data->session = NULL;
644     update_active_session_connection(NULL);
645
646     free(agent_data);
647 }
648
649 void agent_read_complete(struct udscs_connection **connp,
650     struct udscs_message_header *header, uint8_t *data)
651 {
652     struct agent_data *agent_data = udscs_get_user_data(*connp);
653
654     switch (header->type) {
655     case VDAGENTD_GUEST_XORG_RESOLUTION: {
656         struct vdagentd_guest_xorg_resolution *res;
657         int n = header->size / sizeof(*res);
658
659         /* Detect older version session agent, but don't disconnect, as
660            that stops it from getting the VDAGENTD_VERSION message, and then
661            it will never re-exec the new version... */
662         if (header->arg1 == 0 && header->arg2 == 0) {
663             syslog(LOG_INFO, "got old session agent xorg resolution message, "
664                              "ignoring");
665             free(data);
666             return;
667         }
668
669         if (header->size != n * sizeof(*res)) {
670             syslog(LOG_ERR, "guest xorg resolution message has wrong size, "
671                             "disconnecting agent");
672             udscs_destroy_connection(connp);
673             free(data);
674             return;
675         }
676
677         free(agent_data->screen_info);
678         res = malloc(n * sizeof(*res));
679         if (!res) {
680             syslog(LOG_ERR, "out of memory allocating screen info");
681             n = 0;
682         }
683         memcpy(res, data, n * sizeof(*res));
684         agent_data->width  = header->arg1;
685         agent_data->height = header->arg2;
686         agent_data->screen_info  = res;
687         agent_data->screen_count = n;
688
689         check_xorg_resolution();
690         break;
691     }
692     case VDAGENTD_CLIPBOARD_GRAB:
693     case VDAGENTD_CLIPBOARD_REQUEST:
694     case VDAGENTD_CLIPBOARD_DATA:
695     case VDAGENTD_CLIPBOARD_RELEASE:
696         if (do_agent_clipboard(*connp, header, data)) {
697             udscs_destroy_connection(connp);
698             free(data);
699             return;
700         }
701         break;
702     case VDAGENTD_FILE_XFER_STATUS:{
703         VDAgentFileXferStatusMessage status;
704         status.id = header->arg1;
705         status.result = header->arg2;
706         vdagent_virtio_port_write(virtio_port, VDP_CLIENT_PORT,
707                                   VD_AGENT_FILE_XFER_STATUS, 0,
708                                   (uint8_t *)&status, sizeof(status));
709         if (status.result == VD_AGENT_FILE_XFER_STATUS_CAN_SEND_DATA)
710             g_hash_table_insert(active_xfers, GUINT_TO_POINTER(status.id),
711                                 *connp);
712         else
713             g_hash_table_remove(active_xfers, GUINT_TO_POINTER(status.id));
714         break;
715     }
716
717     default:
718         syslog(LOG_ERR, "unknown message from vdagent: %u, ignoring",
719                header->type);
720     }
721     free(data);
722 }
723
724 /* main */
725
726 static void usage(FILE *fp)
727 {
728     fprintf(fp,
729             "Usage: spice-vdagentd [OPTIONS]\n\n"
730             "Spice guest agent daemon, version %s.\n\n"
731             "Options:\n"
732             "  -h             print this text\n"
733             "  -d             log debug messages (use twice for extra info)\n"
734             "  -s <port>      set virtio serial port  [%s]\n"
735             "  -S <filename>  set udcs socket [%s]\n"
736             "  -u <dev>       set uinput device       [%s]\n"
737             "  -x             don't daemonize\n"
738 #ifdef HAVE_CONSOLE_KIT
739             "  -X             Disable console kit integration\n"
740 #endif
741 #ifdef HAVE_LIBSYSTEMD_LOGIN
742             "  -X         Disable systemd-logind integration\n"
743 #endif
744             ,VERSION, portdev, vdagentd_socket, uinput_device);
745 }
746
747 void daemonize(void)
748 {
749     int x;
750     FILE *pidfile;
751
752     /* detach from terminal */
753     switch (fork()) {
754     case 0:
755         close(0); close(1); close(2);
756         setsid();
757         x = open("/dev/null", O_RDWR); x = dup(x); x = dup(x);
758         pidfile = fopen(pidfilename, "w");
759         if (pidfile) {
760             fprintf(pidfile, "%d\n", (int)getpid());
761             fclose(pidfile);
762         }
763         break;
764     case -1:
765         syslog(LOG_ERR, "fork: %m");
766         retval = 1;
767     default:
768         udscs_destroy_server(server);
769         exit(retval);
770     }
771 }
772
773 void main_loop(void)
774 {
775     fd_set readfds, writefds;
776     int n, nfds;
777     int ck_fd = 0;
778
779     while (!quit) {
780         FD_ZERO(&readfds);
781         FD_ZERO(&writefds);
782
783         nfds = udscs_server_fill_fds(server, &readfds, &writefds);
784         n = vdagent_virtio_port_fill_fds(virtio_port, &readfds, &writefds);
785         if (n >= nfds)
786             nfds = n + 1;
787
788         if (session_info) {
789             ck_fd = session_info_get_fd(session_info);
790             FD_SET(ck_fd, &readfds);
791             if (ck_fd >= nfds)
792                 nfds = ck_fd + 1;
793         }
794
795         n = select(nfds, &readfds, &writefds, NULL, NULL);
796         if (n == -1) {
797             if (errno == EINTR)
798                 continue;
799             syslog(LOG_CRIT, "Fatal error select: %m");
800             retval = 1;
801             break;
802         }
803
804         udscs_server_handle_fds(server, &readfds, &writefds);
805
806         if (virtio_port) {
807             vdagent_virtio_port_handle_fds(&virtio_port, &readfds, &writefds);
808             if (!virtio_port) {
809                 int old_client_connected = client_connected;
810                 syslog(LOG_CRIT,
811                        "AIIEEE lost spice client connection, reconnecting");
812                 virtio_port = vdagent_virtio_port_create(portdev,
813                                                      virtio_port_read_complete,
814                                                      NULL);
815                 if (!virtio_port) {
816                     syslog(LOG_CRIT,
817                            "Fatal error opening vdagent virtio channel");
818                     retval = 1;
819                     break;
820                 }
821                 do_client_disconnect();
822                 client_connected = old_client_connected;
823             }
824         }
825
826         if (session_info && FD_ISSET(ck_fd, &readfds)) {
827             active_session = session_info_get_active_session(session_info);
828             update_active_session_connection(NULL);
829         }
830     }
831 }
832
833 static void quit_handler(int sig)
834 {
835     quit = 1;
836 }
837
838 int main(int argc, char *argv[])
839 {
840     int c;
841     int do_daemonize = 1;
842     int want_session_info = 1;
843     struct sigaction act;
844
845     for (;;) {
846         if (-1 == (c = getopt(argc, argv, "-dhxXs:u:S:")))
847             break;
848         switch (c) {
849         case 'd':
850             debug++;
851             break;
852         case 's':
853             portdev = optarg;
854             break;
855         case 'S':
856             vdagentd_socket = optarg;
857             break;
858         case 'u':
859             uinput_device = optarg;
860             break;
861         case 'x':
862             do_daemonize = 0;
863             break;
864         case 'X':
865             want_session_info = 0;
866             break;
867         case 'h':
868             usage(stdout);
869             return 0;
870         default:
871             fputs("\n", stderr);
872             usage(stderr);
873             return 1;
874         }
875     }
876
877     if (strncmp(uinput_device, "/dev", 4) != 0) {
878         syslog(LOG_INFO, "using fake uinput");
879         uinput_fake = 1;
880     }
881
882     memset(&act, 0, sizeof(act));
883     act.sa_flags = SA_RESTART;
884     act.sa_handler = quit_handler;
885     sigaction(SIGINT, &act, NULL);
886     sigaction(SIGHUP, &act, NULL);
887     sigaction(SIGTERM, &act, NULL);
888     sigaction(SIGQUIT, &act, NULL);
889
890     openlog("spice-vdagentd", do_daemonize ? 0 : LOG_PERROR, LOG_USER);
891
892     /* Setup communication with vdagent process(es) */
893     server = udscs_create_server(vdagentd_socket, agent_connect,
894                                  agent_read_complete, agent_disconnect,
895                                  vdagentd_messages, VDAGENTD_NO_MESSAGES,
896                                  debug);
897     if (!server) {
898         syslog(LOG_CRIT, "Fatal could not create server socket %s",
899                vdagentd_socket);
900         return 1;
901     }
902     if (chmod(vdagentd_socket, 0666)) {
903         syslog(LOG_CRIT, "Fatal could not change permissions on %s: %m",
904                vdagentd_socket);
905         udscs_destroy_server(server);
906         return 1;
907     }
908
909     if (do_daemonize)
910         daemonize();
911
912 #ifdef WITH_STATIC_UINPUT
913     uinput = vdagentd_uinput_create(uinput_device, 1024, 768, NULL, 0,
914                                     debug > 1, uinput_fake);
915     if (!uinput) {
916         udscs_destroy_server(server);
917         return 1;
918     }
919 #endif
920
921     if (want_session_info)
922         session_info = session_info_create(debug);
923     if (!session_info)
924         syslog(LOG_WARNING, "no session info, max 1 session agent allowed");
925
926     active_xfers = g_hash_table_new(g_direct_hash, g_direct_equal);
927     main_loop();
928
929     release_clipboards();
930
931     vdagentd_uinput_destroy(&uinput);
932     vdagent_virtio_port_flush(&virtio_port);
933     vdagent_virtio_port_destroy(&virtio_port);
934     session_info_destroy(session_info);
935     udscs_destroy_server(server);
936     if (unlink(vdagentd_socket) != 0)
937         syslog(LOG_ERR, "unlink %s: %s", vdagentd_socket, strerror(errno));
938     syslog(LOG_INFO, "vdagentd quiting, returning status %d", retval);
939
940     if (do_daemonize)
941         unlink(pidfilename);
942
943     return retval;
944 }