VirtualBox

source: vbox/trunk/src/VBox/Additions/linux/lightdm-greeter/vbox-greeter.cpp@ 60441

Last change on this file since 60441 was 57690, checked in by vboxsync, 9 years ago

Additions/vbox-greeter: build fix

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 50.9 KB
Line 
1/* $Id: vbox-greeter.cpp 57690 2015-09-10 13:23:58Z vboxsync $ */
2/** @file
3 * vbox-greeter - an own LightDM greeter module supporting auto-logons
4 * controlled by the host.
5 */
6
7/*
8 * Copyright (C) 2012-2013 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19
20/*********************************************************************************************************************************
21* Header Files *
22*********************************************************************************************************************************/
23#include <pwd.h>
24#include <syslog.h>
25#include <stdlib.h>
26
27#include <lightdm.h>
28#ifdef VBOX_WITH_FLTK
29# include <FL/Fl.H>
30# include <FL/fl_ask.H> /* Yes, the casing is correct for 1.3.0 -- d'oh. */
31# include <FL/Fl_Box.H>
32# include <FL/Fl_Button.H>
33# include <FL/fl_draw.H> /* Same as above. */
34# include <FL/Fl_Double_Window.H>
35# include <FL/Fl_Input.H>
36# include <FL/Fl_Menu_Button.H>
37# ifdef VBOX_GREETER_WITH_PNG_SUPPORT
38# include <FL/Fl_PNG_Image.H>
39# include <FL/Fl_Shared_Image.H>
40# endif
41# include <FL/Fl_Secret_Input.H>
42#else
43# include <cairo-xlib.h>
44# include <gtk/gtk.h>
45# include <gdk/gdkx.h>
46#endif
47
48#include <package-generated.h>
49#include "product-generated.h"
50
51#include <iprt/assert.h>
52#include <iprt/buildconfig.h>
53#include <iprt/env.h>
54#include <iprt/file.h>
55#include <iprt/getopt.h>
56#include <iprt/initterm.h>
57#include <iprt/mem.h>
58#include <iprt/message.h>
59#include <iprt/path.h>
60#include <iprt/process.h>
61#include <iprt/stream.h>
62#include <iprt/system.h>
63#include <iprt/string.h>
64#include <iprt/thread.h>
65#include <iprt/time.h>
66
67#include <VBox/log.h>
68#include <VBox/VBoxGuestLib.h>
69
70/* The greeter's full name for logging. */
71#define VBOX_MODULE_NAME "vbox-lightdm-greeter"
72
73/* UI elements used in this greeter. */
74#define VBOX_GREETER_UI_WND_GREETER "wnd_greeter"
75
76#define VBOX_GREETER_UI_EDT_USER "edt_username"
77#define VBOX_GREETER_UI_EDT_PASSWORD "edt_password"
78#define VBOX_GREETER_UI_BTN_LOGIN "btn_login"
79#define VBOX_GREETER_UI_LBL_INFO "lbl_info"
80
81/* UI display options. */
82/** Show the restart menu entry / button. */
83#define VBOX_GREETER_UI_SHOW_RESTART RT_BIT(0)
84/** Show the shutdown menu entry / button. */
85#define VBOX_GREETER_UI_SHOW_SHUTDOWN RT_BIT(1)
86/** Show the (customized) top banner. */
87#define VBOX_GREETER_UI_SHOW_BANNER RT_BIT(2)
88/** Enable custom colors */
89#define VBOX_GREETER_UI_USE_THEMING RT_BIT(3)
90
91/** Extracts the 8-bit red component from an uint32_t. */
92#define VBOX_RGB_COLOR_RED(uColor) uColor & 0xFF
93/** Extracts the 8-bit green component from an uint32_t. */
94#define VBOX_RGB_COLOR_GREEN(uColor) (uColor >> 8) & 0xFF
95/** Extracts the 8-bit blue component from an uint32_t. */
96#define VBOX_RGB_COLOR_BLUE(uColor) (uColor >> 16) & 0xFF
97
98#include <VBox/log.h>
99#ifdef VBOX_WITH_GUEST_PROPS
100 #include <VBox/HostServices/GuestPropertySvc.h>
101 using namespace guestProp;
102#endif
103
104/** The program name (derived from argv[0]). */
105char *g_pszProgName = (char *)"";
106/** For debugging. */
107#ifdef DEBUG
108 static int g_iVerbosity = 99;
109#else
110 static int g_iVerbosity = 0;
111#endif
112static bool g_fRunning = true;
113
114/** Logging parameters. */
115/** @todo Make this configurable later. */
116static PRTLOGGER g_pLoggerRelease = NULL;
117static uint32_t g_cHistory = 10; /* Enable log rotation, 10 files. */
118static uint32_t g_uHistoryFileTime = RT_SEC_1DAY; /* Max 1 day per file. */
119static uint64_t g_uHistoryFileSize = 100 * _1M; /* Max 100MB per file. */
120
121/**
122 * Context structure which contains all needed
123 * data within callbacks.
124 */
125typedef struct VBOXGREETERCTX
126{
127 /** Pointer to this greeter instance. */
128 LightDMGreeter *pGreeter;
129#ifdef VBOX_WITH_FLTK
130 Fl_Button *pBtnLogin;
131 Fl_Input *pEdtUsername;
132 Fl_Secret_Input *pEdtPassword;
133 Fl_Box *pLblInfo;
134#else
135 /** The GTK builder instance for accessing
136 * the UI elements. */
137 GtkBuilder *pBuilder;
138#endif
139 /** The timeout (in ms) to wait for credentials. */
140 uint32_t uTimeoutMS;
141 /** The starting timestamp (in ms) to calculate
142 * the timeout. */
143 uint64_t uStartMS;
144 /** Timestamp of last abort message. */
145 uint64_t uTsAbort;
146 /** The HGCM client ID. */
147 uint32_t uClientId;
148 /** The credential password. */
149 char *pszPassword;
150} VBOXGREETERCTX, *PVBOXGREETERCTX;
151
152static void vboxGreeterError(const char *pszFormat, ...)
153{
154 va_list va;
155 char *buf;
156 va_start(va, pszFormat);
157 if (RTStrAPrintfV(&buf, pszFormat, va))
158 {
159 RTLogRelPrintf("%s: error: %s", VBOX_MODULE_NAME, buf);
160 RTStrFree(buf);
161 }
162 va_end(va);
163}
164
165static void vboxGreeterLog(const char *pszFormat, ...)
166{
167 if (g_iVerbosity)
168 {
169 va_list va;
170 char *buf;
171 va_start(va, pszFormat);
172 if (RTStrAPrintfV(&buf, pszFormat, va))
173 {
174 /* Only do normal logging in debug mode; could contain
175 * sensitive data! */
176 RTLogRelPrintf("%s: %s", VBOX_MODULE_NAME, buf);
177 RTStrFree(buf);
178 }
179 va_end(va);
180 }
181}
182
183/** @tood Move the following two functions to VbglR3 (also see pam_vbox). */
184#ifdef VBOX_WITH_GUEST_PROPS
185/**
186 * Reads a guest property.
187 *
188 * @return IPRT status code.
189 * @param hPAM PAM handle.
190 * @param uClientID Guest property service client ID.
191 * @param pszKey Key (name) of guest property to read.
192 * @param fReadOnly Indicates whether this key needs to be
193 * checked if it only can be read (and *not* written)
194 * by the guest.
195 * @param pszValue Buffer where to store the key's value.
196 * @param cbValue Size of buffer (in bytes).
197 * @param puTimestamp Timestamp of the value
198 * retrieved. Optional.
199 */
200static int vbox_read_prop(uint32_t uClientID,
201 const char *pszKey, bool fReadOnly,
202 char *pszValue, size_t cbValue, uint64_t *puTimestamp)
203{
204 AssertReturn(uClientID, VERR_INVALID_PARAMETER);
205 AssertPtrReturn(pszKey, VERR_INVALID_POINTER);
206 AssertPtrReturn(pszValue, VERR_INVALID_POINTER);
207 /* puTimestamp is optional. */
208
209 int rc;
210
211 uint64_t u64Timestamp = 0;
212 char *pszValTemp = NULL;
213 char *pszFlags = NULL;
214 /* The buffer for storing the data and its initial size. We leave a bit
215 * of space here in case the maximum values are raised. */
216 void *pvBuf = NULL;
217 uint32_t cbBuf = MAX_VALUE_LEN + MAX_FLAGS_LEN + _1K;
218
219 /* Because there is a race condition between our reading the size of a
220 * property and the guest updating it, we loop a few times here and
221 * hope. Actually this should never go wrong, as we are generous
222 * enough with buffer space. */
223 for (unsigned i = 0; i < 10; i++)
224 {
225 pvBuf = RTMemRealloc(pvBuf, cbBuf);
226 if (pvBuf)
227 {
228 rc = VbglR3GuestPropRead(uClientID, pszKey, pvBuf, cbBuf,
229 &pszValTemp, &u64Timestamp, &pszFlags,
230 &cbBuf);
231 }
232 else
233 rc = VERR_NO_MEMORY;
234
235 switch (rc)
236 {
237 case VERR_BUFFER_OVERFLOW:
238 {
239 /* Buffer too small, try it with a bigger one next time. */
240 cbBuf += _1K;
241 continue; /* Try next round. */
242 }
243
244 default:
245 break;
246 }
247
248 /* Everything except VERR_BUFFER_OVERLOW makes us bail out ... */
249 break;
250 }
251
252 if (RT_SUCCESS(rc))
253 {
254 /* Check security bits. */
255 if (pszFlags)
256 {
257 if ( fReadOnly
258 && !RTStrStr(pszFlags, "RDONLYGUEST"))
259 {
260 /* If we want a property which is read-only on the guest
261 * and it is *not* marked as such, deny access! */
262 rc = VERR_ACCESS_DENIED;
263 }
264 }
265 else /* No flags, no access! */
266 rc = VERR_ACCESS_DENIED;
267
268 if (RT_SUCCESS(rc))
269 {
270 /* If everything went well copy property value to our destination buffer. */
271 if (!RTStrPrintf(pszValue, cbValue, "%s", pszValTemp))
272 rc = VERR_BUFFER_OVERFLOW;
273
274 if (puTimestamp)
275 *puTimestamp = u64Timestamp;
276 }
277 }
278
279#ifdef DEBUG
280 vboxGreeterLog("Read guest property \"%s\"=\"%s\" (Flags: %s, TS: %RU64): %Rrc\n",
281 pszKey, pszValTemp ? pszValTemp : "<None>",
282 pszFlags ? pszFlags : "<None>", u64Timestamp, rc);
283#endif
284
285 if (pvBuf)
286 RTMemFree(pvBuf);
287
288 return rc;
289}
290
291/**
292 * Waits for a guest property to be changed.
293 *
294 * @return IPRT status code.
295 * @param hPAM PAM handle.
296 * @param uClientID Guest property service client ID.
297 * @param pszKey Key (name) of guest property to wait for.
298 * @param uTimeoutMS Timeout (in ms) to wait for the change. Specify
299 * RT_INDEFINITE_WAIT to wait indefinitly.
300 */
301static int vbox_wait_prop(uint32_t uClientID,
302 const char *pszKey, uint32_t uTimeoutMS)
303{
304 AssertReturn(uClientID, VERR_INVALID_PARAMETER);
305 AssertPtrReturn(pszKey, VERR_INVALID_POINTER);
306
307 int rc;
308
309 /* The buffer for storing the data and its initial size. We leave a bit
310 * of space here in case the maximum values are raised. */
311 void *pvBuf = NULL;
312 uint32_t cbBuf = MAX_NAME_LEN + MAX_VALUE_LEN + MAX_FLAGS_LEN + _1K;
313
314 for (int i = 0; i < 10; i++)
315 {
316 void *pvTmpBuf = RTMemRealloc(pvBuf, cbBuf);
317 if (pvTmpBuf)
318 {
319 char *pszName = NULL;
320 char *pszValue = NULL;
321 uint64_t u64TimestampOut = 0;
322 char *pszFlags = NULL;
323
324 pvBuf = pvTmpBuf;
325 rc = VbglR3GuestPropWait(uClientID, pszKey, pvBuf, cbBuf,
326 0 /* Last timestamp; just wait for next event */, uTimeoutMS,
327 &pszName, &pszValue, &u64TimestampOut,
328 &pszFlags, &cbBuf);
329 }
330 else
331 rc = VERR_NO_MEMORY;
332
333 if (rc == VERR_BUFFER_OVERFLOW)
334 {
335 /* Buffer too small, try it with a bigger one next time. */
336 cbBuf += _1K;
337 continue; /* Try next round. */
338 }
339
340 /* Everything except VERR_BUFFER_OVERLOW makes us bail out ... */
341 break;
342 }
343
344 return rc;
345}
346#endif /* VBOX_WITH_GUEST_PROPS */
347
348/**
349 * Checks for credentials provided by the host / HGCM.
350 *
351 * @return IPRT status code. VERR_NOT_FOUND if no credentials are available,
352 * VINF_SUCCESS on successful retrieval or another IPRT error.
353 * @param pCtx Greeter context.
354 */
355static int vboxGreeterCheckCreds(PVBOXGREETERCTX pCtx)
356{
357 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
358
359 static bool s_fCredsNotFoundMsgShown = false;
360 int rc = VbglR3CredentialsQueryAvailability();
361 if (RT_FAILURE(rc))
362 {
363 if (rc != VERR_NOT_FOUND)
364 vboxGreeterError("vboxGreeterCheckCreds: could not query for credentials! rc=%Rrc. Aborting\n", rc);
365 else if (!s_fCredsNotFoundMsgShown)
366 {
367 vboxGreeterLog("vboxGreeterCheckCreds: no credentials available\n");
368 s_fCredsNotFoundMsgShown = true;
369 }
370 }
371 else
372 {
373 /** @todo Domain handling needed? */
374 char *pszUsername; /* User name only is kept local. */
375 char *pszDomain = NULL;
376 rc = VbglR3CredentialsRetrieve(&pszUsername, &pCtx->pszPassword, &pszDomain);
377 if (RT_FAILURE(rc))
378 {
379 vboxGreeterError("vboxGreeterCheckCreds: could not retrieve credentials! rc=%Rrc. Aborting\n", rc);
380 }
381 else
382 {
383 vboxGreeterLog("vboxGreeterCheckCreds: credentials retrieved: user=%s, password=%s, domain=%s\n",
384 pszUsername,
385#ifdef DEBUG
386 pCtx->pszPassword,
387#else
388 "XXX",
389#endif
390 pszDomain);
391 /* Trigger LightDM authentication with the user name just retrieved. */
392 lightdm_greeter_authenticate(pCtx->pGreeter, pszUsername); /* Must be the real user name from host! */
393
394 /* Securely wipe the user name + domain again. */
395 VbglR3CredentialsDestroy(pszUsername, NULL /* pszPassword */, pszDomain,
396 3 /* Three wipe passes */);
397 }
398 }
399
400#ifdef DEBUG
401 vboxGreeterLog("vboxGreeterCheckCreds: returned with rc=%Rrc\n", rc);
402#endif
403 return rc;
404}
405
406/**
407 * Called by LightDM when greeter is not needed anymore.
408 *
409 * @param signum Signal number.
410 */
411static void cb_sigterm(int signum)
412{
413 /* Note: This handler must be reentrant-safe. */
414#ifdef VBOX_WITH_FLTK
415 g_fRunning = false;
416#else
417 exit(RTEXITCODE_SUCCESS);
418#endif
419}
420
421/**
422 * Callback for showing a user prompt, issued by the LightDM server.
423 *
424 * @param pGreeter Pointer to this greeter instance.
425 * @param pszText Text to display.
426 * @param enmType Type of prompt to display.
427 * @param pvData Pointer to user-supplied data.
428 */
429static void cb_lightdm_show_prompt(LightDMGreeter *pGreeter,
430 const gchar *pszText, LightDMPromptType enmType,
431 gpointer pvData)
432{
433 vboxGreeterLog("cb_lightdm_show_prompt: text=%s, type=%d\n", pszText, enmType);
434
435 PVBOXGREETERCTX pCtx = (PVBOXGREETERCTX)pvData;
436 AssertPtr(pCtx);
437
438 switch (enmType)
439 {
440 case 1: /* Password. */
441 {
442 if (pCtx->pszPassword)
443 {
444 lightdm_greeter_respond(pGreeter, pCtx->pszPassword);
445 }
446 else
447 {
448#ifdef VBOX_WITH_FLTK
449 AssertPtr(pCtx->pEdtPassword);
450 const char *pszPwd = pCtx->pEdtPassword->value();
451#else
452 GtkEntry *pEdtPwd = GTK_ENTRY(gtk_builder_get_object(pCtx->pBuilder, "edt_password"));
453 AssertPtr(pEdtPwd);
454 const gchar *pszPwd = gtk_entry_get_text(pEdtPwd);
455#endif
456 lightdm_greeter_respond(pGreeter, pszPwd);
457 }
458 break;
459 }
460 /** @todo Other fields? */
461
462 default:
463 break;
464 }
465
466 VbglR3CredentialsDestroy(NULL /* pszUsername */, pCtx->pszPassword, NULL /* pszDomain */,
467 3 /* Three wipe passes */);
468 pCtx->pszPassword = NULL;
469}
470
471/**
472 * Callback for showing a message, issued by the LightDM server.
473 *
474 * @param pGreeter Pointer to this greeter instance.
475 * @param pszText Text to display.
476 * @param enmType Type of message to display.
477 * @param pvData Pointer to user-supplied data.
478 */
479static void cb_lightdm_show_message(LightDMGreeter *pGreeter,
480 const gchar *pszText, LightDMPromptType enmType,
481 gpointer pvData)
482{
483 vboxGreeterLog("cb_lightdm_show_message: text=%s, type=%d\n", pszText, enmType);
484
485 PVBOXGREETERCTX pCtx = (PVBOXGREETERCTX)pvData;
486 AssertPtrReturnVoid(pCtx);
487
488#ifdef VBOX_WITH_FLTK
489 AssertPtr(pCtx->pLblInfo);
490 pCtx->pLblInfo->copy_label(pszText);
491#else
492 GtkLabel *pLblInfo = GTK_LABEL(gtk_builder_get_object(pCtx->pBuilder, "lbl_info"));
493 AssertPtr(pLblInfo);
494 gtk_label_set_text(pLblInfo, pszText);
495#endif
496}
497
498/**
499 * Callback for authentication completion, issued by the LightDM server.
500 *
501 * @param pGreeter Pointer to this greeter instance.
502 */
503static void cb_lightdm_auth_complete(LightDMGreeter *pGreeter)
504{
505 vboxGreeterLog("cb_lightdm_auth_complete\n");
506
507 const gchar *pszUser = lightdm_greeter_get_authentication_user(pGreeter);
508 vboxGreeterLog("authenticating user: %s\n", pszUser ? pszUser : "<NULL>");
509
510 if (lightdm_greeter_get_is_authenticated(pGreeter))
511 {
512 /** @todo Add non-default session support. */
513 gchar *pszSession = g_strdup(lightdm_greeter_get_default_session_hint(pGreeter));
514 if (pszSession)
515 {
516 vboxGreeterLog("starting session: %s\n", pszSession);
517 GError *pError = NULL;
518 if (!lightdm_greeter_start_session_sync(pGreeter, pszSession, &pError))
519 {
520 vboxGreeterError("unable to start session '%s': %s\n",
521 pszSession, pError ? pError->message : "Unknown error");
522 }
523 else
524 {
525 AssertPtr(pszSession);
526 vboxGreeterLog("session '%s' successfully started\n", pszSession);
527 }
528 if (pError)
529 g_error_free(pError);
530 g_free(pszSession);
531 }
532 else
533 vboxGreeterError("unable to get default session\n");
534 }
535 else
536 vboxGreeterLog("user not authenticated successfully (yet)\n");
537}
538
539/**
540 * Callback for clicking on the "Login" button.
541 *
542 * @param pWidget Widget this callback is bound to.
543 * @param pvData Pointer to user-supplied data.
544 */
545#ifdef VBOX_WITH_FLTK
546void cb_btn_login(Fl_Widget *pWidget, void *pvData)
547#else
548void cb_btn_login(GtkWidget *pWidget, gpointer pvData)
549#endif
550{
551 PVBOXGREETERCTX pCtx = (PVBOXGREETERCTX)pvData;
552 AssertPtr(pCtx);
553
554#ifdef VBOX_WITH_FLTK
555 AssertPtr(pCtx->pEdtUsername);
556 const char *pszUser = pCtx->pEdtUsername->value();
557 AssertPtr(pCtx->pEdtPassword);
558 const char *pszPwd = pCtx->pEdtPassword->value();
559#else
560 GtkEntry *pEdtUser = GTK_ENTRY(gtk_builder_get_object(pCtx->pBuilder, VBOX_GREETER_UI_EDT_USER));
561 AssertPtr(pEdtUser);
562 const gchar *pszUser = gtk_entry_get_text(pEdtUser);
563
564 GtkEntry *pEdtPwd = GTK_ENTRY(gtk_builder_get_object(pCtx->pBuilder, VBOX_GREETER_UI_EDT_PASSWORD));
565 AssertPtr(pEdtPwd);
566 const gchar *pszPwd = gtk_entry_get_text(pEdtPwd);
567#endif
568
569 /** @todo Add domain handling? */
570 vboxGreeterLog("login button pressed: greeter=%p, user=%s, password=%s\n",
571 pCtx->pGreeter,
572 pszUser ? pszUser : "<NONE>",
573#ifdef DEBUG
574 pszPwd ? pszPwd : "<NONE>");
575#else
576 /* Don't log passwords in release mode! */
577 "XXX");
578#endif
579 if (strlen(pszUser)) /* Only authenticate if username is given. */
580 {
581 lightdm_greeter_respond(pCtx->pGreeter, pszPwd);
582 lightdm_greeter_authenticate(pCtx->pGreeter, pszUser);
583 }
584}
585
586/**
587 * Callback for clicking on the "Menu" button.
588 *
589 * @param pWidget Widget this callback is bound to.
590 * @param pvData Pointer to user-supplied data.
591 */
592#ifdef VBOX_WITH_FLTK
593void cb_btn_menu(Fl_Widget *pWidget, void *pvData)
594#else
595void cb_btn_menu(GtkWidget *pWidget, gpointer pvData)
596#endif
597{
598 vboxGreeterLog("menu button pressed\n");
599}
600
601/**
602 * Callback for clicking on the "Restart" button / menu entry.
603 *
604 * @param pWidget Widget this callback is bound to.
605 * @param pvData Pointer to user-supplied data.
606 */
607#ifdef VBOX_WITH_FLTK
608void cb_btn_restart(Fl_Widget *pWidget, void *pvData)
609#else
610void cb_btn_restart(GtkWidget *pWidget, gpointer pvData)
611#endif
612{
613 vboxGreeterLog("restart button pressed\n");
614
615 bool fRestart = true;
616#ifdef VBOX_WITH_FLTK
617 int rc = fl_choice("Really restart the system?", "Yes", "No", NULL);
618 fRestart = rc == 0;
619#endif
620
621 if (fRestart)
622 {
623 vboxGreeterLog("restart requested\n");
624#ifndef DEBUG
625 lightdm_restart(NULL);
626#endif
627 }
628}
629
630/**
631 * Callback for clicking on the "Shutdown" button / menu entry.
632 *
633 * @param pWidget Widget this callback is bound to.
634 * @param pvData Pointer to user-supplied data.
635 */
636#ifdef VBOX_WITH_FLTK
637void cb_btn_shutdown(Fl_Widget *pWidget, void *pvData)
638#else
639void cb_btn_shutdown(GtkWidget *pWidget, gpointer pvData)
640#endif
641{
642 vboxGreeterLog("shutdown button pressed\n");
643
644 bool fShutdown = true;
645#ifdef VBOX_WITH_FLTK
646 int rc = fl_choice("Really shutdown the system?", "Yes", "No", NULL);
647 fShutdown = rc == 0;
648#endif
649
650 if (fShutdown)
651 {
652 vboxGreeterLog("shutdown requested\n");
653#ifndef DEBUG
654 lightdm_shutdown(NULL);
655#endif
656 }
657}
658
659#ifdef VBOX_WITH_FLTK
660void cb_edt_username(Fl_Widget *pWidget, void *pvData)
661#else
662void cb_edt_username(GtkWidget *pWidget, gpointer pvData)
663#endif
664{
665 vboxGreeterLog("cb_edt_username called\n");
666
667 PVBOXGREETERCTX pCtx = (PVBOXGREETERCTX)pvData;
668 AssertPtr(pCtx);
669#ifdef VBOX_WITH_FLTK
670 AssertPtr(pCtx->pEdtPassword);
671 Fl::focus(pCtx->pEdtPassword);
672#endif
673}
674
675#ifdef VBOX_WITH_FLTK
676void cb_edt_password(Fl_Widget *pWidget, void *pvData)
677#else
678void cb_edt_password(GtkWidget *pWidget, gpointer pvData)
679#endif
680{
681 vboxGreeterLog("cb_edt_password called\n");
682
683 PVBOXGREETERCTX pCtx = (PVBOXGREETERCTX)pvData;
684 AssertPtr(pCtx);
685#ifdef VBOX_WITH_FLTK
686 AssertPtr(pCtx->pBtnLogin);
687 cb_btn_login(pCtx->pBtnLogin, pvData);
688#endif
689}
690
691/**
692 * Callback for the timer event which is checking for new credentials
693 * from the host.
694 *
695 * @param pvData Pointer to user-supplied data.
696 */
697#ifdef VBOX_WITH_FLTK
698static void cb_check_creds(void *pvData)
699#else
700static gboolean cb_check_creds(gpointer pvData)
701#endif
702{
703 PVBOXGREETERCTX pCtx = (PVBOXGREETERCTX)pvData;
704 AssertPtr(pCtx);
705
706#ifdef DEBUG
707 vboxGreeterLog("cb_check_creds called, clientId=%RU32, timeoutMS=%RU32\n",
708 pCtx->uClientId, pCtx->uTimeoutMS);
709#endif
710
711 int rc = VINF_SUCCESS;
712
713#ifdef VBOX_WITH_GUEST_PROPS
714 bool fAbort = false;
715 char szVal[255];
716 if (pCtx->uClientId)
717 {
718 uint64_t tsAbort;
719 rc = vbox_read_prop(pCtx->uClientId,
720 "/VirtualBox/GuestAdd/PAM/CredsWaitAbort",
721 true /* Read-only on guest */,
722 szVal, sizeof(szVal), &tsAbort);
723 switch (rc)
724 {
725 case VINF_SUCCESS:
726# ifdef DEBUG
727 vboxGreeterLog("cb_check_creds: tsAbort %RU64 <-> %RU64\n",
728 pCtx->uTsAbort, tsAbort);
729# endif
730 if (tsAbort != pCtx->uTsAbort)
731 fAbort = true; /* Timestamps differs, abort. */
732 pCtx->uTsAbort = tsAbort;
733 break;
734
735 case VERR_TOO_MUCH_DATA:
736 vboxGreeterError("cb_check_creds: temporarily unable to get abort notification\n");
737 break;
738
739 case VERR_NOT_FOUND:
740 /* Value not found, continue checking for credentials. */
741 break;
742
743 default:
744 vboxGreeterError("cb_check_creds: the abort notification request failed with rc=%Rrc\n", rc);
745 fAbort = true; /* Abort on error. */
746 break;
747 }
748 }
749
750 if (fAbort)
751 {
752 /* Get optional message. */
753 szVal[0] = '\0';
754 int rc2 = vbox_read_prop(pCtx->uClientId,
755 "/VirtualBox/GuestAdd/PAM/CredsMsgWaitAbort",
756 true /* Read-only on guest */,
757 szVal, sizeof(szVal), NULL /* Timestamp. */);
758 if ( RT_FAILURE(rc2)
759 && rc2 != VERR_NOT_FOUND)
760 vboxGreeterError("cb_check_creds: getting wait abort message failed with rc=%Rrc\n", rc2);
761# ifdef VBOX_WITH_FLTK
762 AssertPtr(pCtx->pLblInfo);
763 pCtx->pLblInfo->copy_label(szVal);
764# else /* !VBOX_WITH_FLTK */
765 GtkLabel *pLblInfo = GTK_LABEL(gtk_builder_get_object(pCtx->pBuilder, VBOX_GREETER_UI_LBL_INFO));
766 AssertPtr(pLblInfo);
767 gtk_label_set_text(pLblInfo, szVal);
768# endif /* !VBOX_WITH_FLTK */
769 vboxGreeterLog("cb_check_creds: got notification from host to abort waiting\n");
770 }
771 else
772 {
773#endif /* VBOX_WITH_GUEST_PROPS */
774 rc = vboxGreeterCheckCreds(pCtx);
775 if (RT_SUCCESS(rc))
776 {
777 /* Credentials retrieved. */
778 }
779 else if (rc == VERR_NOT_FOUND)
780 {
781 /* No credentials found, but try next round (if there's
782 * time left for) ... */
783 }
784#ifdef VBOX_WITH_GUEST_PROPS
785 }
786#endif /* VBOX_WITH_GUEST_PROPS */
787
788 if (rc == VERR_NOT_FOUND) /* No credential found this round. */
789 {
790 /* Calculate timeout value left after process has been started. */
791 uint64_t u64Elapsed = RTTimeMilliTS() - pCtx->uStartMS;
792 /* Is it time to bail out? */
793 if (pCtx->uTimeoutMS < u64Elapsed)
794 {
795#ifdef VBOX_WITH_GUEST_PROPS
796 szVal[0] = '\0';
797 int rc2 = vbox_read_prop(pCtx->uClientId,
798 "/VirtualBox/GuestAdd/PAM/CredsMsgWaitTimeout",
799 true /* Read-only on guest */,
800 szVal, sizeof(szVal), NULL /* Timestamp. */);
801 if ( RT_FAILURE(rc2)
802 && rc2 != VERR_NOT_FOUND)
803 vboxGreeterError("cb_check_creds: getting wait timeout message failed with rc=%Rrc\n", rc2);
804# ifdef VBOX_WITH_FLTK
805 AssertPtr(pCtx->pLblInfo);
806 pCtx->pLblInfo->copy_label(szVal);
807# else
808 GtkLabel *pLblInfo = GTK_LABEL(gtk_builder_get_object(pCtx->pBuilder, VBOX_GREETER_UI_LBL_INFO));
809 AssertPtr(pLblInfo);
810 gtk_label_set_text(pLblInfo, szVal);
811# endif
812#endif /* VBOX_WITH_GUEST_PROPS */
813 vboxGreeterLog("cb_check_creds: no credentials retrieved within time (%RU32ms), giving up\n",
814 pCtx->uTimeoutMS);
815 rc = VERR_TIMEOUT;
816 }
817 }
818
819#ifdef DEBUG
820 vboxGreeterLog("cb_check_creds returned with rc=%Rrc\n", rc);
821#endif
822
823 /* At the moment we only allow *one* shot from the host,
824 * so setting credentials in a second attempt won't be possible
825 * intentionally. */
826
827 if (rc == VERR_NOT_FOUND)
828#ifdef VBOX_WITH_FLTK
829 Fl::repeat_timeout(0.5 /* 500 ms */, cb_check_creds, pvData);
830#else
831 return TRUE; /* No credentials found, do another round. */
832
833 return FALSE; /* Remove timer source on every other error / status. */
834#endif
835}
836
837/**
838 * Release logger callback.
839 *
840 * @return IPRT status code.
841 * @param pLoggerRelease
842 * @param enmPhase
843 * @param pfnLog
844 */
845static DECLCALLBACK(void) vboxGreeterLogHeaderFooter(PRTLOGGER pLoggerRelease, RTLOGPHASE enmPhase, PFNRTLOGPHASEMSG pfnLog)
846{
847 /* Some introductory information. */
848 static RTTIMESPEC s_TimeSpec;
849 char szTmp[256];
850 if (enmPhase == RTLOGPHASE_BEGIN)
851 RTTimeNow(&s_TimeSpec);
852 RTTimeSpecToString(&s_TimeSpec, szTmp, sizeof(szTmp));
853
854 switch (enmPhase)
855 {
856 case RTLOGPHASE_BEGIN:
857 {
858 pfnLog(pLoggerRelease,
859 "vbox-greeter %s r%s (verbosity: %d) %s (%s %s) release log\n"
860 "Log opened %s\n",
861 RTBldCfgVersion(), RTBldCfgRevisionStr(), g_iVerbosity, VBOX_BUILD_TARGET,
862 __DATE__, __TIME__, szTmp);
863
864 int vrc = RTSystemQueryOSInfo(RTSYSOSINFO_PRODUCT, szTmp, sizeof(szTmp));
865 if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW)
866 pfnLog(pLoggerRelease, "OS Product: %s\n", szTmp);
867 vrc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szTmp, sizeof(szTmp));
868 if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW)
869 pfnLog(pLoggerRelease, "OS Release: %s\n", szTmp);
870 vrc = RTSystemQueryOSInfo(RTSYSOSINFO_VERSION, szTmp, sizeof(szTmp));
871 if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW)
872 pfnLog(pLoggerRelease, "OS Version: %s\n", szTmp);
873 if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW)
874 pfnLog(pLoggerRelease, "OS Service Pack: %s\n", szTmp);
875
876 /* the package type is interesting for Linux distributions */
877 char szExecName[RTPATH_MAX];
878 char *pszExecName = RTProcGetExecutablePath(szExecName, sizeof(szExecName));
879 pfnLog(pLoggerRelease,
880 "Executable: %s\n"
881 "Process ID: %u\n"
882 "Package type: %s"
883#ifdef VBOX_OSE
884 " (OSE)"
885#endif
886 "\n",
887 pszExecName ? pszExecName : "unknown",
888 RTProcSelf(),
889 VBOX_PACKAGE_STRING);
890 break;
891 }
892
893 case RTLOGPHASE_PREROTATE:
894 pfnLog(pLoggerRelease, "Log rotated - Log started %s\n", szTmp);
895 break;
896
897 case RTLOGPHASE_POSTROTATE:
898 pfnLog(pLoggerRelease, "Log continuation - Log started %s\n", szTmp);
899 break;
900
901 case RTLOGPHASE_END:
902 pfnLog(pLoggerRelease, "End of log file - Log started %s\n", szTmp);
903 break;
904
905 default:
906 /* nothing */;
907 }
908}
909
910/**
911 * Creates the default release logger outputting to the specified file.
912 *
913 * @return IPRT status code.
914 * @param pszLogFile Filename for log output. Optional.
915 */
916static int vboxGreeterLogCreate(const char *pszLogFile)
917{
918 /* Create release logger (stdout + file). */
919 static const char * const s_apszGroups[] = VBOX_LOGGROUP_NAMES;
920 RTUINT fFlags = RTLOGFLAGS_PREFIX_THREAD | RTLOGFLAGS_PREFIX_TIME_PROG;
921#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
922 fFlags |= RTLOGFLAGS_USECRLF;
923#endif
924 char szError[RTPATH_MAX + 128] = "";
925 int rc = RTLogCreateEx(&g_pLoggerRelease, fFlags, "all",
926 "VBOXGREETER_RELEASE_LOG", RT_ELEMENTS(s_apszGroups), s_apszGroups,
927 RTLOGDEST_STDOUT,
928 vboxGreeterLogHeaderFooter, g_cHistory, g_uHistoryFileSize, g_uHistoryFileTime,
929 szError, sizeof(szError), pszLogFile);
930 if (RT_SUCCESS(rc))
931 {
932 /* register this logger as the release logger */
933 RTLogRelSetDefaultInstance(g_pLoggerRelease);
934
935 /* Explicitly flush the log in case of VBOXGREETER_RELEASE_LOG_FLAGS=buffered. */
936 RTLogFlush(g_pLoggerRelease);
937 }
938
939 return rc;
940}
941
942static void vboxGreeterLogDestroy(void)
943{
944 RTLogDestroy(RTLogRelSetDefaultInstance(NULL));
945}
946
947static int vboxGreeterUsage(void)
948{
949 RTPrintf("Usage:\n"
950 " %-12s [-h|-?|--help] [-F|--logfile <file>]\n"
951 " [-v|--verbose] [-V|--version]\n", g_pszProgName);
952
953 RTPrintf("\n"
954 " Copyright (C) 2012-" VBOX_C_YEAR " " VBOX_VENDOR "\n");
955
956 return RTEXITCODE_SYNTAX;
957}
958
959int main(int argc, char **argv)
960{
961 int rc = RTR3InitExe(argc, &argv, 0);
962 if (RT_FAILURE(rc))
963 return RTMsgInitFailure(rc);
964 g_pszProgName = RTPathFilename(argv[0]);
965
966 static const RTGETOPTDEF s_aOptions[] =
967 {
968 { "--logfile", 'F', RTGETOPT_REQ_STRING },
969 { "--verbose", 'v', RTGETOPT_REQ_NOTHING },
970 { "--version", 'V', RTGETOPT_REQ_NOTHING }
971 };
972
973 char szLogFile[RTPATH_MAX + 128] = "";
974
975 int ch;
976 RTGETOPTUNION ValueUnion;
977 RTGETOPTSTATE GetState;
978 RTGetOptInit(&GetState, argc, argv,
979 s_aOptions, RT_ELEMENTS(s_aOptions),
980 1 /*iFirst*/, RTGETOPTINIT_FLAGS_OPTS_FIRST);
981
982 while ( (ch = RTGetOpt(&GetState, &ValueUnion))
983 && RT_SUCCESS(rc))
984 {
985 /* For options that require an argument, ValueUnion has received the value. */
986 switch (ch)
987 {
988 case 'F':
989 if (!RTStrPrintf(szLogFile, sizeof(szLogFile), "%s", ValueUnion.psz))
990 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to get prepare log file name");
991 break;
992
993 case 'h':
994 case '?':
995 return vboxGreeterUsage();
996
997 case 'v': /* Raise verbosity. */
998 g_iVerbosity++;
999 break;
1000
1001 case 'V': /* Print version and exit. */
1002 RTPrintf("%sr%s\n", RTBldCfgVersion(), RTBldCfgRevisionStr());
1003 return RTEXITCODE_SUCCESS;
1004 break; /* Never reached. */
1005
1006 default:
1007 return RTGetOptPrintError(ch, &ValueUnion);
1008 }
1009 }
1010
1011 if (RT_FAILURE(rc))
1012 return RTEXITCODE_SYNTAX;
1013
1014 rc = VbglR3InitUser();
1015 if (RT_FAILURE(rc))
1016 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to init Vbgl (%Rrc)", rc);
1017
1018 rc = vboxGreeterLogCreate(strlen(szLogFile) ? szLogFile : NULL);
1019 if (RT_FAILURE(rc))
1020 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to create release log (%s, %Rrc)",
1021 strlen(szLogFile) ? szLogFile : "<None>", rc);
1022
1023 vboxGreeterLog("init\n");
1024
1025 signal(SIGTERM, cb_sigterm);
1026
1027 /** @todo This function already is too long. Move code into
1028 * functions. */
1029
1030 VBOXGREETERCTX ctx;
1031 RT_ZERO(ctx);
1032
1033 /* UI parameters. */
1034 uint32_t uBgColor = 0; /* The background color. */
1035 uint32_t uLogonDlgHdrColor = 0;
1036 uint32_t uLogonDlgBgColor = 0; /* The greeter's dialog color. */
1037 uint32_t uLogonDlgBtnColor = 0; /* The greeter's button color. */
1038
1039#ifdef VBOX_GREETER_WITH_PNG_SUPPORT
1040 char szBannerPath[RTPATH_MAX];
1041#endif
1042
1043 /* By default most UI elements are shown. */
1044 uint32_t uOptsUI = VBOX_GREETER_UI_SHOW_RESTART
1045 | VBOX_GREETER_UI_SHOW_SHUTDOWN;
1046#ifdef VBOX_WITH_GUEST_PROPS
1047 uint32_t uClientId = 0;
1048 rc = VbglR3GuestPropConnect(&uClientId);
1049 if (RT_SUCCESS(rc))
1050 {
1051 vboxGreeterLog("clientId=%RU32\n", uClientId);
1052
1053 ctx.uClientId = uClientId;
1054
1055 char szVal[256];
1056 int rc2 = vbox_read_prop(uClientId,
1057 "/VirtualBox/GuestAdd/Greeter/HideRestart",
1058 true /* Read-only on guest */,
1059 szVal, sizeof(szVal), NULL /* Timestamp. */);
1060 if ( RT_SUCCESS(rc2)
1061 && !RTStrICmp(szVal, "1"))
1062 {
1063 uOptsUI &= ~VBOX_GREETER_UI_SHOW_RESTART;
1064 }
1065
1066 rc2 = vbox_read_prop(uClientId,
1067 "/VirtualBox/GuestAdd/Greeter/HideShutdown",
1068 true /* Read-only on guest */,
1069 szVal, sizeof(szVal), NULL /* Timestamp. */);
1070 if ( RT_SUCCESS(rc2)
1071 && !RTStrICmp(szVal, "1"))
1072 {
1073 uOptsUI &= ~VBOX_GREETER_UI_SHOW_SHUTDOWN;
1074 }
1075
1076# ifdef VBOX_GREETER_WITH_PNG_SUPPORT
1077 /* Load the banner. */
1078 rc2 = vbox_read_prop(uClientId,
1079 "/VirtualBox/GuestAdd/Greeter/BannerPath",
1080 true /* Read-only on guest */,
1081 szBannerPath, sizeof(szBannerPath), NULL /* Timestamp. */);
1082 if (RT_SUCCESS(rc2))
1083 {
1084 if (RTFileExists(szBannerPath))
1085 {
1086 vboxGreeterLog("showing banner from '%s'\n", szBannerPath);
1087 uOptsUI |= VBOX_GREETER_UI_SHOW_BANNER;
1088 }
1089 else
1090 vboxGreeterLog("warning: unable to find banner at '%s', skipping\n", szBannerPath);
1091 }
1092# endif /* VBOX_GREETER_WITH_PNG_SUPPORT */
1093
1094 /* Use theming?. */
1095 rc2 = vbox_read_prop(uClientId,
1096 "/VirtualBox/GuestAdd/Greeter/UseTheming",
1097 true /* Read-only on guest */,
1098 szVal, sizeof(szVal), NULL /* Timestamp. */);
1099 if ( RT_SUCCESS(rc2)
1100 && !RTStrICmp(szVal, "1"))
1101 {
1102 vboxGreeterLog("custom theming enabled\n");
1103 uOptsUI |= VBOX_GREETER_UI_USE_THEMING;
1104 }
1105
1106 if (uOptsUI & VBOX_GREETER_UI_USE_THEMING)
1107 {
1108 /* Get background color. */
1109 rc2 = vbox_read_prop(uClientId,
1110 "/VirtualBox/GuestAdd/Greeter/Theme/BackgroundColor",
1111 true /* Read-only on guest */,
1112 szVal, sizeof(szVal), NULL /* Timestamp. */);
1113 if (RT_SUCCESS(rc2))
1114 {
1115 uBgColor = strtol(szVal, NULL,
1116 /* Change conversion base when having a 0x prefix. */
1117 RTStrStr(szVal, "0x") == szVal ? 0 : 16);
1118 }
1119
1120 /* Logon dialog. */
1121
1122 /* Get header color. */
1123 rc2 = vbox_read_prop(uClientId,
1124 "/VirtualBox/GuestAdd/Greeter/Theme/LogonDialog/HeaderColor",
1125 true /* Read-only on guest */,
1126 szVal, sizeof(szVal), NULL /* Timestamp. */);
1127 if (RT_SUCCESS(rc2))
1128 {
1129 uLogonDlgHdrColor = strtol(szVal, NULL,
1130 /* Change conversion base when having a 0x prefix. */
1131 RTStrStr(szVal, "0x") == szVal ? 0 : 16);
1132 }
1133
1134 /* Get dialog color. */
1135 rc2 = vbox_read_prop(uClientId,
1136 "/VirtualBox/GuestAdd/Greeter/Theme/LogonDialog/BackgroundColor",
1137 true /* Read-only on guest */,
1138 szVal, sizeof(szVal), NULL /* Timestamp. */);
1139 if (RT_SUCCESS(rc2))
1140 {
1141 uLogonDlgBgColor = strtol(szVal, NULL,
1142 /* Change conversion base when having a 0x prefix. */
1143 RTStrStr(szVal, "0x") == szVal ? 0 : 16);
1144 }
1145
1146 /* Get button color. */
1147 rc2 = vbox_read_prop(uClientId,
1148 "/VirtualBox/GuestAdd/Greeter/Theme/LogonDialog/ButtonColor",
1149 true /* Read-only on guest */,
1150 szVal, sizeof(szVal), NULL /* Timestamp. */);
1151 if (RT_SUCCESS(rc2))
1152 {
1153 uLogonDlgBtnColor = strtol(szVal, NULL,
1154 /* Change conversion base when having a 0x prefix. */
1155 RTStrStr(szVal, "0x") == szVal ? 0 : 16);
1156 }
1157 }
1158 }
1159 else
1160 vboxGreeterError("unable to connect to guest property service, rc=%Rrc\n", rc);
1161#endif
1162 vboxGreeterLog("UI options are: %RU32\n", uOptsUI);
1163
1164#ifdef VBOX_WITH_FLTK
1165 int rc2 = Fl::scheme("plastic");
1166 if (!rc2)
1167 vboxGreeterLog("warning: unable to set visual scheme\n");
1168
1169 Fl::visual(FL_DOUBLE | FL_INDEX);
1170 Fl_Double_Window *pWndMain = new Fl_Double_Window(Fl::w(), Fl::h(), "VirtualBox Guest Additions");
1171 AssertPtr(pWndMain);
1172 if (uOptsUI & VBOX_GREETER_UI_USE_THEMING)
1173 pWndMain->color(fl_rgb_color(VBOX_RGB_COLOR_RED(uBgColor),
1174 VBOX_RGB_COLOR_GREEN(uBgColor),
1175 VBOX_RGB_COLOR_BLUE(uBgColor)));
1176 else /* Default colors. */
1177 pWndMain->color(fl_rgb_color(0x73, 0x7F, 0x8C));
1178
1179 Fl_Double_Window *pWndGreeter = new Fl_Double_Window(500, 350);
1180 AssertPtr(pWndGreeter);
1181 pWndGreeter->set_modal();
1182 if (uOptsUI & VBOX_GREETER_UI_USE_THEMING)
1183 pWndGreeter->color(fl_rgb_color(VBOX_RGB_COLOR_RED(uLogonDlgBgColor),
1184 VBOX_RGB_COLOR_GREEN(uLogonDlgBgColor),
1185 VBOX_RGB_COLOR_BLUE(uLogonDlgBgColor)));
1186 else /* Default colors. */
1187 pWndGreeter->color(fl_rgb_color(255, 255, 255));
1188
1189 uint32_t uOffsetX = 130;
1190 /**
1191 * For now we're using a simple Y offset for moving all elements
1192 * down if a banner needs to be shown on top of the greeter. Not
1193 * very clean but does the job. Use some more layouting stuff
1194 * when this gets more complex.
1195 */
1196 uint32_t uOffsetY = 80;
1197
1198# ifdef VBOX_GREETER_WITH_PNG_SUPPORT
1199 fl_register_images();
1200
1201 /** @todo Add basic image type detection based on file
1202 * extension. */
1203
1204 Fl_PNG_Image *pImgBanner = NULL;
1205 if (uOptsUI & VBOX_GREETER_UI_SHOW_BANNER)
1206 {
1207 pImgBanner = new Fl_PNG_Image(szBannerPath);
1208 AssertPtr(pImgBanner);
1209
1210 /** @todo Make the banner size configurable via guest
1211 * properties. For now it's hardcoded to 460 x 90px. */
1212 Fl_Box *pBoxBanner = new Fl_Box(20, uOffsetY, 460, 90, "");
1213 AssertPtr(pBoxBanner);
1214 pBoxBanner->image(pImgBanner);
1215
1216 uOffsetY = 120;
1217 }
1218# endif
1219
1220 Fl_Box *pLblHeader = new Fl_Box(FL_NO_BOX, 242, uOffsetY, 300, 20,
1221 "Desktop Login");
1222 AssertPtr(pLblHeader);
1223
1224 /** Note to use an own font:
1225 * Fl_Font myfnt = FL_FREE_FONT + 1;
1226 * Fl::set_font(myfnt, "MyFont"); */
1227 Fl_Font fntHeader = FL_FREE_FONT;
1228 Fl::set_font(fntHeader, "Courier");
1229
1230 pLblHeader->align(FL_ALIGN_LEFT);
1231 pLblHeader->labelfont(FL_BOLD);
1232 pLblHeader->labelsize(24);
1233 if (uOptsUI & VBOX_GREETER_UI_USE_THEMING)
1234 pLblHeader->labelcolor(fl_rgb_color(VBOX_RGB_COLOR_RED(uLogonDlgHdrColor),
1235 VBOX_RGB_COLOR_GREEN(uLogonDlgHdrColor),
1236 VBOX_RGB_COLOR_BLUE(uLogonDlgHdrColor)));
1237 else /* Default color. */
1238 pLblHeader->labelcolor(fl_rgb_color(0x51, 0x5F, 0x77));
1239 uOffsetY += 40;
1240
1241 /** @todo Add basic NLS support. */
1242
1243 Fl_Input *pEdtUsername = new Fl_Input(uOffsetX, uOffsetY,
1244 300, 20, "User Name");
1245 AssertPtr(pEdtUsername);
1246 pEdtUsername->callback(cb_edt_username, &ctx);
1247 pEdtUsername->when(FL_WHEN_ENTER_KEY_ALWAYS);
1248 Fl::focus(pEdtUsername);
1249 ctx.pEdtUsername = pEdtUsername;
1250
1251 Fl_Secret_Input *pEdtPassword = new Fl_Secret_Input(uOffsetX, uOffsetY + 40,
1252 300, 20, "Password");
1253 AssertPtr(pEdtPassword);
1254 pEdtPassword->callback(cb_edt_password, &ctx);
1255 pEdtPassword->when(FL_WHEN_ENTER_KEY_ALWAYS);
1256 ctx.pEdtPassword = pEdtPassword;
1257
1258 Fl_Button *pBtnLogin = new Fl_Button(uOffsetX, uOffsetY + 70,
1259 100, 40, "Log In");
1260 AssertPtr(pBtnLogin);
1261 pBtnLogin->callback(cb_btn_login, &ctx);
1262 if (uOptsUI & VBOX_GREETER_UI_USE_THEMING)
1263 pBtnLogin->color(fl_rgb_color(VBOX_RGB_COLOR_RED(uLogonDlgBtnColor),
1264 VBOX_RGB_COLOR_GREEN(uLogonDlgBtnColor),
1265 VBOX_RGB_COLOR_BLUE(uLogonDlgBtnColor)));
1266 else /* Default color. */
1267 pBtnLogin->color(fl_rgb_color(255, 255, 255));
1268 ctx.pBtnLogin = pBtnLogin;
1269
1270 Fl_Menu_Button *pBtnMenu = new Fl_Menu_Button(uOffsetX + 120, uOffsetY + 70,
1271 100, 40, "Options");
1272 AssertPtr(pBtnMenu);
1273 pBtnMenu->callback(cb_btn_menu, &ctx);
1274 if (uOptsUI & VBOX_GREETER_UI_USE_THEMING)
1275 pBtnMenu->color(fl_rgb_color(VBOX_RGB_COLOR_RED(uLogonDlgBtnColor),
1276 VBOX_RGB_COLOR_GREEN(uLogonDlgBtnColor),
1277 VBOX_RGB_COLOR_BLUE(uLogonDlgBtnColor)));
1278 else /* Default color. */
1279 pBtnMenu->color(fl_rgb_color(255, 255, 255));
1280
1281 if (uOptsUI & VBOX_GREETER_UI_SHOW_RESTART)
1282 pBtnMenu->add("Restart", "" /* Shortcut */, cb_btn_restart, &ctx, 0 /* Flags */);
1283 if (uOptsUI & VBOX_GREETER_UI_SHOW_SHUTDOWN)
1284 pBtnMenu->add("Shutdown", "" /* Shortcut */, cb_btn_shutdown, &ctx, 0 /* Flags */);
1285
1286 char szLabel[255];
1287 RTStrPrintf(szLabel, sizeof(szLabel), "Oracle VM VirtualBox Guest Additions %sr%s",
1288 RTBldCfgVersion(), RTBldCfgRevisionStr());
1289 Fl_Box *pLblInfo = new Fl_Box(FL_NO_BOX , 50, uOffsetY + 150,
1290 400, 20, szLabel);
1291 AssertPtr(pLblInfo);
1292 ctx.pLblInfo = pLblInfo;
1293
1294 pWndGreeter->end();
1295 pWndGreeter->position((Fl::w() - pWndGreeter->w()) / 2,
1296 (Fl::h() - pWndGreeter->h()) / 2);
1297
1298 pWndMain->fullscreen();
1299 pWndMain->show(argc, argv);
1300 pWndMain->end();
1301
1302 pWndGreeter->show();
1303#else /* !VBOX_WITH_FLTK */
1304 gtk_init(&argc, &argv);
1305
1306 /* Set default cursor */
1307 gdk_window_set_cursor(gdk_get_default_root_window(), gdk_cursor_new(GDK_LEFT_PTR));
1308
1309 GError *pError = NULL;
1310 GtkBuilder *pBuilder = gtk_builder_new();
1311 AssertPtr(pBuilder);
1312 if (!gtk_builder_add_from_file(pBuilder, "/usr/share/xgreeters/vbox-greeter.ui", &pError))
1313 {
1314 AssertPtr(pError);
1315 vboxGreeterError("unable to load UI: %s", pError->message);
1316 return RTEXITCODE_FAILURE;
1317 }
1318
1319 GtkWindow *pWndGreeter = GTK_WINDOW(gtk_builder_get_object(pBuilder, VBOX_GREETER_UI_WND_GREETER));
1320 AssertPtr(pWndGreeter);
1321 GtkButton *pBtnLogin = GTK_BUTTON(gtk_builder_get_object(pBuilder, VBOX_GREETER_UI_BTN_LOGIN));
1322 AssertPtr(pBtnLogin);
1323 GtkLabel *pLblInfo = GTK_LABEL(gtk_builder_get_object(pBuilder, VBOX_GREETER_UI_LBL_INFO));
1324 AssertPtr(pLblInfo);
1325
1326 ctx.pBuilder = pBuilder;
1327
1328 g_signal_connect(G_OBJECT(pBtnLogin), "clicked", G_CALLBACK(cb_btn_login), &ctx);
1329
1330 GdkRectangle rectScreen;
1331 gdk_screen_get_monitor_geometry(gdk_screen_get_default(), gdk_screen_get_primary_monitor(gdk_screen_get_default()), &rectScreen);
1332 vboxGreeterLog("monitor (default) is %dx%d\n", rectScreen.width, rectScreen.height);
1333
1334 gint iWndX, iWndY;
1335 gtk_window_get_default_size(pWndGreeter, &iWndX, &iWndY);
1336 vboxGreeterLog("greeter is %dx%d\n", iWndX, iWndY);
1337
1338 gtk_window_move(pWndGreeter,
1339 (rectScreen.width / 2) - (iWndX / 2),
1340 (rectScreen.height / 2) - (iWndY / 2));
1341 gtk_widget_show(GTK_WIDGET(pWndGreeter));
1342
1343 g_clear_error(&pError);
1344#endif /* !VBOX_WITH_FLTK */
1345
1346 /* GType is needed in any case (for LightDM), whether we
1347 * use GTK3 or not. */
1348 g_type_init();
1349
1350 GMainLoop *pMainLoop = g_main_loop_new(NULL, FALSE /* Not yet running */);
1351 AssertPtr(pMainLoop);
1352
1353 LightDMGreeter *pGreeter = lightdm_greeter_new();
1354 AssertPtr(pGreeter);
1355
1356 g_signal_connect(pGreeter, "show-prompt", G_CALLBACK(cb_lightdm_show_prompt), &ctx);
1357 g_signal_connect(pGreeter, "show-message", G_CALLBACK(cb_lightdm_show_message), &ctx);
1358 g_signal_connect(pGreeter, "authentication-complete", G_CALLBACK(cb_lightdm_auth_complete), &ctx);
1359
1360 ctx.pGreeter = pGreeter;
1361
1362 if (!lightdm_greeter_connect_sync(pGreeter, NULL))
1363 {
1364 vboxGreeterError("unable to connect to LightDM server, aborting\n");
1365 return RTEXITCODE_FAILURE;
1366 }
1367
1368 vboxGreeterLog("connected to LightDM server\n");
1369
1370#ifdef VBOX_WITH_GUEST_PROPS
1371 bool fCheckCreds = false;
1372 if (uClientId) /* Connected to guest property service? */
1373 {
1374 char szVal[256];
1375 rc2 = vbox_read_prop(uClientId,
1376 "/VirtualBox/GuestAdd/PAM/CredsWait",
1377 true /* Read-only on guest */,
1378 szVal, sizeof(szVal), NULL /* Timestamp. */);
1379 if (RT_SUCCESS(rc2))
1380 {
1381 uint32_t uTimeoutMS = RT_INDEFINITE_WAIT; /* Wait infinite by default. */
1382 rc2 = vbox_read_prop(uClientId,
1383 "/VirtualBox/GuestAdd/PAM/CredsWaitTimeout",
1384 true /* Read-only on guest */,
1385 szVal, sizeof(szVal), NULL /* Timestamp. */);
1386 if (RT_SUCCESS(rc2))
1387 {
1388 uTimeoutMS = RTStrToUInt32(szVal);
1389 if (!uTimeoutMS)
1390 {
1391 vboxGreeterError("pam_vbox_authenticate: invalid waiting timeout value specified, defaulting to infinite timeout\n");
1392 uTimeoutMS = RT_INDEFINITE_WAIT;
1393 }
1394 else
1395 uTimeoutMS = uTimeoutMS * 1000; /* Make ms out of s. */
1396 }
1397
1398 ctx.uTimeoutMS = uTimeoutMS;
1399
1400 rc2 = vbox_read_prop(uClientId,
1401 "/VirtualBox/GuestAdd/PAM/CredsMsgWaiting",
1402 true /* Read-only on guest */,
1403 szVal, sizeof(szVal), NULL /* Timestamp. */);
1404 if (RT_SUCCESS(rc2))
1405 {
1406# ifdef VBOX_WITH_FLTK
1407 Assert(pLblInfo);
1408 pLblInfo->copy_label(szVal);
1409# else
1410 gtk_label_set_text(pLblInfo, szVal);
1411# endif
1412 }
1413
1414 /* Get initial timestamp so that we can compare the time
1415 * whether the value has been changed or not in our event callback. */
1416 vbox_read_prop(uClientId,
1417 "/VirtualBox/GuestAdd/PAM/CredsWaitAbort",
1418 true /* Read-only on guest */,
1419 szVal, sizeof(szVal), &ctx.uTsAbort);
1420
1421 if (RT_SUCCESS(rc))
1422 {
1423 /* Before we actuall wait for credentials just make sure we didn't already get credentials
1424 * set so that we can skip waiting for them ... */
1425 rc2 = vboxGreeterCheckCreds(&ctx);
1426 if (rc2 == VERR_NOT_FOUND)
1427 {
1428 /* Get current time stamp to later calculate rest of timeout left. */
1429 ctx.uStartMS = RTTimeMilliTS();
1430
1431 fCheckCreds = true;
1432 }
1433 }
1434 }
1435
1436 /* Start the timer to check credentials availability. */
1437 if (fCheckCreds)
1438 {
1439 vboxGreeterLog("No credentials available on startup, starting to check periodically ...\n");
1440# ifdef VBOX_WITH_FLTK
1441 Fl::add_timeout(0.5 /* 500 ms */, cb_check_creds, &ctx);
1442# else
1443 g_timeout_add(500 /* ms */, (GSourceFunc)cb_check_creds, &ctx);
1444# endif
1445 }
1446 }
1447#endif /* VBOX_WITH_GUEST_PROPS */
1448
1449#ifdef VBOX_WITH_FLTK
1450 /*
1451 * Do own GDK main loop processing because FLTK also needs
1452 * to have the chance of processing its events.
1453 */
1454 GMainContext *pMainCtx = g_main_context_default();
1455 AssertPtr(pMainCtx);
1456
1457 while (g_fRunning)
1458 {
1459 g_main_context_iteration(pMainCtx,
1460 FALSE /* No blocking */);
1461 Fl::check();
1462 RTThreadSleep(10); /* Wait a bit, don't hog the CPU too much. */
1463 }
1464
1465 g_main_context_unref(pMainCtx);
1466
1467# ifdef VBOX_GREETER_WITH_PNG_SUPPORT
1468 if (pImgBanner)
1469 {
1470 delete pImgBanner; /* Call destructor to free bitmap data. */
1471 pImgBanner = NULL;
1472 }
1473# endif /* VBOX_GREETER_WITH_PNG_SUPPORT */
1474#else /* !VBOX_WITH_FLTK */
1475 gtk_main();
1476 /** @todo Never reached so far. LightDM sends a SIGTERM. */
1477#endif /* !VBOX_WITH_FLTK */
1478
1479 vboxGreeterLog("terminating\n");
1480
1481#ifdef VBOX_WITH_GUEST_PROPS
1482 if (uClientId)
1483 {
1484 rc2 = VbglR3GuestPropDisconnect(uClientId);
1485 AssertRC(rc2);
1486 }
1487#endif /* VBOX_WITH_GUEST_PROPS */
1488
1489 VbglR3Term();
1490
1491 RTEXITCODE rcExit = RT_SUCCESS(rc)
1492 ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1493
1494 vboxGreeterLog("terminated with exit code %ld (rc=%Rrc)\n",
1495 rcExit, rc);
1496
1497 vboxGreeterLogDestroy();
1498
1499 return rcExit;
1500}
1501
1502#ifdef DEBUG
1503DECLEXPORT(void) RTAssertMsg1Weak(const char *pszExpr, unsigned uLine, const char *pszFile, const char *pszFunction)
1504{
1505 RTAssertMsg1(pszExpr, uLine, pszFile, pszFunction);
1506}
1507#endif
1508
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette